Skip to content

Commit

Permalink
[FEAT] Add experimental support for writing PAM modules
Browse files Browse the repository at this point in the history
  • Loading branch information
1wilkens committed May 4, 2020
1 parent 067d2a1 commit 0836c81
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Add Cargo features for `auth` (default) and `module`
- Add internal `pam-macros` crate (experimental for now)
- Reexport `pam_sys` at crate root
- Add experimental support for modules via `PamModule` trait and `impl_pam_module` macro

### Changed
- Change `Authenticator::get_handler` to `Authenticator::handler_mut` and add `Authenticator::handler` for immutable access to the handler
Expand Down
8 changes: 7 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,16 @@ auth = ["users"]
module = []

[dependencies]
pam-macros = "=0.0.1"
pam-macros = "=0.0.2"
libc = "^0.2"
pam-sys = "1.0.0-alpha2"
users = { version = "^0.9", optional = true }

[dev-dependencies]
rpassword = "2.0"

[workspace]
members = [
".",
"macros"
]
2 changes: 1 addition & 1 deletion src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ impl<'a> Authenticator<'a, conv::PasswordConv> {
}

impl<'a, C: conv::Conversation> Authenticator<'a, C> {
/// Creates a new Authenticator with a given service name and conversation callback
/// Create a new Authenticator with a given service name and conversation callback
pub fn with_handler(service: &str, conversation: C) -> PamResult<Authenticator<'a, C>> {
let mut conversation = Box::new(conversation);
let conv = conv::into_pam_conv(&mut *conversation);
Expand Down
2 changes: 1 addition & 1 deletion src/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ pub enum PamReturnCode {
Try_Again,

/// Ignore underlying account module regardless of whether
/// the control flag is required as isize, optional as isize, or sufficient
/// the control flag is required, optional, or sufficient
Ignore,

/// Critical error (?module fail now request)
Expand Down
123 changes: 123 additions & 0 deletions src/module.rs
Original file line number Diff line number Diff line change
@@ -1 +1,124 @@
//! Functions and structures that can be used to implement a PAM module
//!
//! Inspired by anowell/pam-rs
use crate::{PamHandle, PamReturnCode};
use std::ffi::CStr;
use std::os::raw::c_uint;

// FIXME: Find a solution for the flags containing ORed integers
#[allow(unused_variables)]
/// Trait representing a PAM module.
///
/// Modules should override the desired functions and call the macro `impl_pam_module`.
/// This exports the respective functions at the expected symbols prefixed with `pam_sm_`.
pub trait PamModule {
fn account_management(handle: &PamHandle, args: Vec<&CStr>, flags: c_uint) -> PamReturnCode {
PamReturnCode::Ignore
}
fn authenticate(handle: &PamHandle, args: Vec<&CStr>, flags: c_uint) -> PamReturnCode {
PamReturnCode::Ignore
}
fn change_auth_token(handle: &PamHandle, args: Vec<&CStr>, flags: c_uint) -> PamReturnCode {
PamReturnCode::Ignore
}
fn close_session(handle: &PamHandle, args: Vec<&CStr>, flags: c_uint) -> PamReturnCode {
PamReturnCode::Ignore
}
fn open_session(handle: &PamHandle, args: Vec<&CStr>, flags: c_uint) -> PamReturnCode {
PamReturnCode::Ignore
}
fn set_credentials(handle: &PamHandle, args: Vec<&CStr>, flags: c_uint) -> PamReturnCode {
PamReturnCode::Ignore
}
}

#[macro_export]
macro_rules! impl_pam_module {
($struct:ident) => {
pub use _pam_module_::*;
mod _pam_module_ {
use crate::{module::PamModule, PamHandle, PamReturnCode};
use std::ffi::CStr;
use std::os::raw::{c_char, c_int, c_uint};

fn convert_args<'a>(argc: c_int, argv: *const *const c_char) -> Vec<&'a CStr> {
(0..argc)
.map(|i| unsafe { CStr::from_ptr(*argv.offset(i as isize)) })
.collect()
}

#[no_mangle]
pub extern "C" fn pam_sm_acct_mgmt(
handle: &PamHandle,
flags: c_uint,
argc: c_int,
argv: *const *const c_char,
) -> PamReturnCode {
let args = convert_args(argc, argv);
super::$struct::account_management(handle, args, flags)
}
#[no_mangle]
pub extern "C" fn pam_sm_authenticate(
handle: &PamHandle,
flags: c_uint,
argc: c_int,
argv: *const *const c_char,
) -> PamReturnCode {
let args = convert_args(argc, argv);
super::$struct::authenticate(handle, args, flags)
}
#[no_mangle]
pub extern "C" fn pam_sm_chauthtok(
handle: &PamHandle,
flags: c_uint,
argc: c_int,
argv: *const *const c_char,
) -> PamReturnCode {
let args = convert_args(argc, argv);
super::$struct::change_auth_token(handle, args, flags)
}
#[no_mangle]
pub extern "C" fn pam_sm_close_session(
handle: &PamHandle,
flags: c_uint,
argc: c_int,
argv: *const *const c_char,
) -> PamReturnCode {
let args = convert_args(argc, argv);
super::$struct::close_session(handle, args, flags)
}
#[no_mangle]
pub extern "C" fn pam_sm_open_session(
handle: &PamHandle,
flags: c_uint,
argc: c_int,
argv: *const *const c_char,
) -> PamReturnCode {
let args = convert_args(argc, argv);
super::$struct::open_session(handle, args, flags)
}
#[no_mangle]
pub extern "C" fn pam_sm_setcred(
handle: &PamHandle,
flags: c_uint,
argc: c_int,
argv: *const *const c_char,
) -> PamReturnCode {
let args = convert_args(argc, argv);
super::$struct::set_credentials(handle, args, flags)
}
}
};
}

#[cfg(test)]
pub mod test {
use super::PamModule;
use crate::impl_pam_module;

pub struct TestModule;
impl PamModule for TestModule {}

impl_pam_module!(TestModule);
}

0 comments on commit 0836c81

Please sign in to comment.