Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose PamEnvList and PamEnvIter API #15

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ This project adheres to [Semantic Versioning](http://semver.org/).
-->

## [Unreleased]
### Added
- Add API for interacting with the PAM environment (needs some more tests)
- Add `Authenticator::environment` function.
- Add `PamEnvIter` struct
- Add `PamEnvList::iter` function to iterate over the `&CStr`'s in the environment list.
- Add implementation of `FusedIterator` for `PamEnvIter`
### Changed
- Move CI to azure pipelines (and remove `.travis.yml`)

Expand All @@ -20,6 +26,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).

### Changed
- Change `Authenticator::get_handler` to `Authenticator::handler_mut` and add `Authenticator::handler` for immutable access to the handler
- Change `PamEnvList` to public and re-export env module at library root

## [0.7.0] - 2019-02-07
### Added
Expand Down
18 changes: 13 additions & 5 deletions src/authenticator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use users;

use std::{env, ptr};

use crate::{env::get_pam_env, ffi, Converse, PamError, PamResult, PasswordConv};
use crate::{env::get_pam_env, env::PamEnvList, ffi, Converse, PamError, PamResult, PasswordConv};

/// Main struct to authenticate a user
///
Expand Down Expand Up @@ -73,6 +73,10 @@ impl<'a, C: Converse> Authenticator<'a, C> {
}
}

pub fn environment(&mut self) -> Option<PamEnvList> {
get_pam_env(self.handle)
}

/// Mutable access to the conversation handler of this Authenticator
pub fn handler_mut(&mut self) -> &mut C {
&mut *self.converse
Expand Down Expand Up @@ -135,10 +139,14 @@ impl<'a, C: Converse> Authenticator<'a, C> {
use users::os::unix::UserExt;

// Set PAM environment in the local process
if let Some(mut env_list) = get_pam_env(self.handle) {
let env = env_list.to_vec();
for (key, value) in env {
env::set_var(&key, &value);
if let Some(env) = self.environment() {
for name_value in env.iter() {
let split = name_value.to_string_lossy();
let mut split = split.splitn(2, '=');

if let (Some(key), Some(value)) = (split.next(), split.next()) {
env::set_var(&key, &value);
}
}
}

Expand Down
60 changes: 38 additions & 22 deletions src/env.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
use libc::{c_char, free};
use pam_sys::{getenvlist, raw, PamHandle};

use core::iter::FusedIterator;
use std::ffi::CStr;

pub struct PamEnvList {
ptr: *const *const c_char,
}

pub fn get_pam_env(handle: &mut PamHandle) -> Option<PamEnvList> {
pub struct PamEnvIter<'a> {
envs: &'a PamEnvList,
idx: isize,
ended: bool,
}

pub(crate) fn get_pam_env(handle: &mut PamHandle) -> Option<PamEnvList> {
let env = getenvlist(handle);
if !env.is_null() {
Some(PamEnvList { ptr: env })
Expand All @@ -17,32 +24,41 @@ pub fn get_pam_env(handle: &mut PamHandle) -> Option<PamEnvList> {
}

impl PamEnvList {
pub fn to_vec(&mut self) -> Vec<(String, String)> {
let mut vec = Vec::new();

let mut idx = 0;
loop {
let env_ptr: *const *const c_char = unsafe { self.ptr.offset(idx) };
if unsafe { !(*env_ptr).is_null() } {
idx += 1;

let env = unsafe { CStr::from_ptr(*env_ptr) }.to_string_lossy();
let split: Vec<_> = env.splitn(2, '=').collect();

if split.len() == 2 {
// Only add valid env vars (contain at least one '=')
vec.push((split[0].into(), split[1].into()));
}
} else {
// Reached the end of the env array -> break out of the loop
break;
}
pub fn iter(&self) -> PamEnvIter {
PamEnvIter {
envs: self,
idx: 0,
ended: false,
}
}

pub fn as_ptr(&self) -> *const *const c_char {
self.ptr
}
}

impl<'a> Iterator for PamEnvIter<'a> {
type Item = &'a CStr;

fn next(&mut self) -> Option<&'a CStr> {
if self.ended {
return None;
}

vec
let env_ptr = unsafe { self.envs.ptr.offset(self.idx) };
self.idx += 1;

if env_ptr.is_null() || unsafe { (*env_ptr).is_null() } {
self.ended = true;
None
} else {
Some(unsafe { CStr::from_ptr(*env_ptr) })
}
}
}

impl FusedIterator for PamEnvIter<'_> {}

#[cfg(target_os = "linux")]
impl Drop for PamEnvList {
fn drop(&mut self) {
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use pam_sys::PamReturnCode;
use std::ffi::{CStr, CString};

pub use crate::authenticator::*;
pub use crate::env::*;

pub struct PamError(PamReturnCode);
pub type PamResult<T> = std::result::Result<T, PamError>;
Expand Down