use libc::c_char;
use memchr::memchr;
use std::vec::IntoIter;
use std::ffi::{CStr, OsString};
pub struct PamEnvList {
inner: IntoIter<(OsString, OsString)>
}
impl Iterator for PamEnvList {
type Item = (String, String);
fn next(&mut self) -> Option<(String, String)> {
self.inner.next().map(|(a, b)| (a.into_string().unwrap(), b.into_string().unwrap()))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
impl PamEnvList {
pub(crate) fn from_ptr(ptr: *const *const c_char) -> PamEnvList {
let mut result = Vec::new();
unsafe {
let mut current = ptr;
if !current.is_null() {
while !(*current).is_null() {
if let Some(key_value) = parse_env_line(CStr::from_ptr(*current).to_bytes()) {
result.push(key_value);
}
current = current.add(1);
}
}
}
drop_env_list(ptr);
return PamEnvList { inner: result.into_iter() };
}
}
fn parse_env_line(input: &[u8]) -> Option<(OsString, OsString)> {
use std::os::unix::prelude::OsStringExt;
if input.is_empty() {
return None;
}
let pos = memchr(b'=', input).map(|p| p + 1);
pos.map(|p| {
(
OsStringExt::from_vec(input[..p].to_vec()),
OsStringExt::from_vec(input[p + 1..].to_vec()),
)
})
}
#[cfg(target_os = "linux")]
fn drop_env_list(ptr: *const *const c_char) {
unsafe { crate::ffi::pam_misc_drop_env(ptr as *mut *mut c_char) };
}
#[cfg(not(target_os = "linux"))]
fn drop_env_list(ptr: *const *const c_char) {
let mut cur = *ptr;
while !ptr.is_null() {
unsafe { free(ptr) };
ptr = ptr.add(1);
}
unsafe { free(ptr) };
}