view pam-http/src/lib.rs @ 34:ec70822cbdef

Overhaul
author Andy Caldwell <andrew.caldwell@metaswitch.com>
date Sun, 24 Apr 2022 03:42:11 +0100
parents 4263c1d83d5b
children
line wrap: on
line source

extern crate pam;
extern crate reqwest;

use pam::constants::{PamFlag, PamResultCode, PAM_PROMPT_ECHO_OFF};
use pam::conv::Conv;
use pam::module::{PamHandle, PamHooks};
use reqwest::blocking::Client;
use reqwest::StatusCode;
use std::collections::HashMap;
use std::ffi::CStr;
use std::time::Duration;
use pam::pam_try;

struct PamHttp;
pam::pam_hooks!(PamHttp);

impl PamHooks for PamHttp {
    // This function performs the task of authenticating the user.
    fn sm_authenticate(pamh: &mut PamHandle, args: Vec<&CStr>, _flags: PamFlag) -> PamResultCode {
        println!("Let's auth over HTTP");

        let args: Vec<_> = args
            .iter()
            .map(|s| s.to_string_lossy())
            .collect();
        let args: HashMap<&str, &str> = args
            .iter()
            .map(|s| {
                let mut parts = s.splitn(2, '=');
                (parts.next().unwrap(), parts.next().unwrap_or(""))
            })
            .collect();

        let user = pam_try!(pamh.get_user(None));

        let url: &str = match args.get("url") {
            Some(url) => url,
            None => return PamResultCode::PAM_AUTH_ERR,
        };

        let conv = match pamh.get_item::<Conv>() {
            Ok(Some(conv)) => conv,
            Ok(None) => {
                unreachable!("No conv available");
            }
            Err(err) => {
                println!("Couldn't get pam_conv");
                return err;
            }
        };
        let password = pam_try!(conv.send(PAM_PROMPT_ECHO_OFF, "Word, yo: "));
        let password = match password {
            Some(password) => Some(pam_try!(password.to_str(), PamResultCode::PAM_AUTH_ERR)),
            None => None,
        };
        println!("Got a password {:?}", password);
        let status = pam_try!(
            get_url(url, &user, password),
            PamResultCode::PAM_AUTH_ERR
        );

        if !status.is_success() {
            println!("HTTP Error: {}", status);
            return PamResultCode::PAM_AUTH_ERR;
        }

        PamResultCode::PAM_SUCCESS
    }

    fn sm_setcred(_pamh: &mut PamHandle, _args: Vec<&CStr>, _flags: PamFlag) -> PamResultCode {
        println!("set credentials");
        PamResultCode::PAM_SUCCESS
    }

    fn acct_mgmt(_pamh: &mut PamHandle, _args: Vec<&CStr>, _flags: PamFlag) -> PamResultCode {
        println!("account management");
        PamResultCode::PAM_SUCCESS
    }
}

fn get_url(url: &str, user: &str, password: Option<&str>) -> reqwest::Result<StatusCode> {
    let client = Client::builder().timeout(Duration::from_secs(15)).build()?;
    client
        .get(url)
        .basic_auth(user, password)
        .send()
        .map(|r| r.status())
}