From f3a3b600d6cbbc7221f4b430654fa8982d83f341 Mon Sep 17 00:00:00 2001 From: shimun Date: Fri, 3 Apr 2020 01:39:04 +0200 Subject: [PATCH] parse pam config args --- src/lib.rs | 73 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 9c53561..7166a0f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,12 +1,14 @@ #[macro_use] extern crate pamsm; extern crate ctap_hmac as ctap; -use ctap::{get_assertion_devices, FidoAssertionRequestBuilder, FidoDevice}; +use ctap::{get_assertion_devices, FidoAssertionRequestBuilder, FidoDevice, FidoErrorKind}; use pamsm::{Pam, PamError, PamFlag, PamServiceModule}; use rand::Rng; use regex::Regex; +use std::collections::HashMap; use std::fs::File; -use std::io::{self, prelude::*, BufReader}; +use std::io::{prelude::*, BufReader}; +use std::path::Path; use std::time::{Duration, SystemTime}; struct PamFido2; @@ -26,26 +28,50 @@ impl Default for Settings { } impl Settings { - pub fn load() -> Settings { + pub fn from_args(args: Vec) -> Self { + let args = args + .into_iter() + .filter_map(|arg| { + let mut parts = arg.split("="); + parts + .by_ref() + .next() + .map(|key| (key.to_string(), parts.collect::>().join("="))) + }) + .collect::>(); + let mut settings = Settings::load( + args.get("authfile") + .map(AsRef::as_ref) + .unwrap_or("/etc/fido2_pam.conf"), + ); + let timeout = args + .get("timeout") + .map(|t| { + t.parse::() + .expect("invalid config timeout is supposed to be an int") + }) + .map(Duration::from_secs); + if let Some(timeout) = timeout { + settings.device_timeout = timeout; + }; + settings + } + pub fn load(path: impl AsRef) -> Settings { let mut creds = Vec::new(); - for path in &["./pam_fido2.conf", "/etc/pam_fido2.conf"] { - let file = match File::open(&path) { - Ok(file) => file, - _ => continue, - }; - let reader = BufReader::new(file); + let file = File::open(path.as_ref()).unwrap(); + let reader = BufReader::new(file); - for line in reader.lines() { - let line = line.unwrap(); - let mut parts = line.split(":"); - if let Some(user) = parts.by_ref().next() { - creds.push(( - (&parts.collect::>()[..].join(":")).to_string(), - user.to_string(), - )); - } + for line in reader.lines() { + let line = line.unwrap(); + let mut parts = line.split(":"); + if let Some(user) = parts.by_ref().next() { + creds.push(( + (&parts.collect::>()[..].join(":")).to_string(), + user.to_string(), + )); } } + Settings { user_credentials: creds, ..Default::default() @@ -71,15 +97,9 @@ impl Settings { } } -impl PamFido2 { - fn settings(&self) -> Settings { - Settings::load() - } -} - impl PamServiceModule for PamFido2 { - fn authenticate(self: &Self, pamh: Pam, _: PamFlag, _args: Vec) -> PamError { - let settings = self.settings(); + fn authenticate(self: &Self, pamh: Pam, _: PamFlag, args: Vec) -> PamError { + let settings = Settings::from_args(args); let begin = SystemTime::now(); let challenge = rand::thread_rng().gen::<[u8; 32]>(); let credentials = settings.get_credentials( @@ -111,6 +131,7 @@ impl PamServiceModule for PamFido2 { Err(_) if begin.elapsed().unwrap() > settings.device_timeout => { return PamError::AUTH_ERR } + Err(e) if e.kind() == FidoErrorKind::DeviceUnsupported => continue, Err(e) => eprintln!("{:?}", e), } }