#![allow(non_camel_case_types)]
#![allow(clippy::upper_case_acronyms)]
use pam_types::PamHandle;
use std::fmt;
use std::os::raw::c_int;
#[repr(transparent)]
pub struct Pam(pub(crate) PamHandle);
impl Pam {
pub fn as_send_ref(&mut self) -> PamSendRef<'_> {
PamSendRef(self)
}
}
impl<'a> From<&'a mut Pam> for PamSendRef<'a> {
fn from(value: &'a mut Pam) -> Self {
Self(value)
}
}
pub struct PamSendRef<'a>(&'a mut Pam);
unsafe impl<'a> Send for PamSendRef<'a> {}
impl std::ops::Deref for PamSendRef<'_> {
type Target = Pam;
fn deref(&self) -> &Self::Target {
self.0
}
}
impl<'a> From<PamSendRef<'a>> for &'a mut Pam {
fn from(value: PamSendRef<'a>) -> Self {
value.0
}
}
impl<'a> From<PamSendRef<'a>> for &'a Pam {
fn from(value: PamSendRef<'a>) -> Self {
value.0
}
}
bitflags! {
pub struct PamFlags : c_int {
const DATA_REPLACE = 0x2000_0000;
const SILENT = 0x8000;
const DISALLOW_NULL_AUTHTOK = 0x0001;
const ESTABLISH_CRED = 0x0002;
const DELETE_CRED = 0x0004;
const REINITIALIZE_CRED = 0x0008;
const REFRESH_CRED = 0x0010;
const CHANGE_EXPIRED_AUTHTOK = 0x0020;
}
}
impl fmt::Display for PamError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
}
}
macro_rules! int_enum {
( $name:ident ($ukey:ident = $uvalue:expr) {
$( $key:ident = $value:expr ),*
}) => {
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum $name {
$( $key = $value, )*
$ukey = $uvalue,
}
impl $name {
#[cfg(feature = "libpam")]
pub(crate) fn new(r: c_int) -> $name {
match r {
$( $value => $name::$key, )*
_ => $name::$ukey,
}
}
}
}
}
int_enum! {
PamError (UNKNOWN_RESULT = -1) {
SUCCESS = 0,
OPEN_ERR = 1,
SYMBOL_ERR = 2,
SERVICE_ERR = 3,
SYSTEM_ERR = 4,
BUF_ERR = 5,
PERM_DENIED = 6,
AUTH_ERR = 7,
CRED_INSUFFICIENT = 8,
AUTHINFO_UNAVAIL = 9,
USER_UNKNOWN = 10,
MAXTRIES = 11,
NEW_AUTHTOK_REQD = 12,
ACCT_EXPIRED = 13,
SESSION_ERR = 14,
CRED_UNAVAIL = 15,
CRED_EXPIRED = 16,
CRED_ERR = 17,
NO_MODULE_DATA = 18,
CONV_ERR = 19,
AUTHTOK_ERR = 20,
AUTHTOK_RECOVERY_ERR = 21,
AUTHTOK_LOCK_BUSY = 22,
AUTHTOK_DISABLE_AGING = 23,
TRY_AGAIN = 24,
IGNORE = 25,
ABORT = 26,
AUTHTOK_EXPIRED = 27,
MODULE_UNKNOWN = 28,
BAD_ITEM = 29,
CONV_AGAIN = 30,
INCOMPLETE = 31
}
}
pub trait PamServiceModule {
fn open_session(_: Pam, _: PamFlags, _: Vec<String>) -> PamError {
PamError::SERVICE_ERR
}
fn close_session(_: Pam, _: PamFlags, _: Vec<String>) -> PamError {
PamError::SERVICE_ERR
}
fn authenticate(_: Pam, _: PamFlags, _: Vec<String>) -> PamError {
PamError::SERVICE_ERR
}
fn setcred(_: Pam, _: PamFlags, _: Vec<String>) -> PamError {
PamError::SERVICE_ERR
}
fn acct_mgmt(_: Pam, _: PamFlags, _: Vec<String>) -> PamError {
PamError::SERVICE_ERR
}
fn chauthtok(_: Pam, _: PamFlags, _: Vec<String>) -> PamError {
PamError::SERVICE_ERR
}
}
#[macro_export]
macro_rules! pam_module {
($pamsm_ty:ty) => {
fn _check_pamsm_trait<T: pamsm::PamServiceModule>() {}
fn _t() {
_check_pamsm_trait::<$pamsm_ty>()
}
macro_rules! pam_callback {
($pam_cb:ident, $rust_cb:ident) => {
#[no_mangle]
#[doc(hidden)]
pub unsafe extern "C" fn $pam_cb(
pamh: pamsm::Pam,
flags: std::os::raw::c_int,
argc: std::os::raw::c_int,
argv: *const *const std::os::raw::c_char,
) -> std::os::raw::c_int {
use std::os::raw::c_int;
if argc < 0 {
return pamsm::PamError::SERVICE_ERR as std::os::raw::c_int;
}
let mut args = Vec::<String>::with_capacity(argc as usize);
for count in 0..(argc as isize) {
match {
std::ffi::CStr::from_ptr(
*argv.offset(count) as *const std::os::raw::c_char
)
.to_str()
} {
Ok(s) => args.push(s.to_owned()),
Err(_) => return pamsm::PamError::SERVICE_ERR as c_int,
};
}
<$pamsm_ty>::$rust_cb(pamh, pamsm::PamFlags::from_bits_unchecked(flags), args) as c_int
}
};
}
pam_callback!(pam_sm_open_session, open_session);
pam_callback!(pam_sm_close_session, close_session);
pam_callback!(pam_sm_authenticate, authenticate);
pam_callback!(pam_sm_setcred, setcred);
pam_callback!(pam_sm_acct_mgmt, acct_mgmt);
pam_callback!(pam_sm_chauthtok, chauthtok);
};
}