feat: clone from: https://github.com/anowell/pam-rs
This commit is contained in:
12
pam-http/Cargo.toml
Normal file
12
pam-http/Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "pam-http"
|
||||
version = "0.1.0"
|
||||
authors = ["Anthony Nowell <anowell@gmail.com>"]
|
||||
|
||||
[lib]
|
||||
name = "pam_http"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
pam-bindings = { path = "../pam/" }
|
||||
reqwest = { version = "0.11.3", features = ["blocking"] }
|
||||
12
pam-http/Justfile
Normal file
12
pam-http/Justfile
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
all:
|
||||
cargo build
|
||||
|
||||
install:
|
||||
@cargo build --release
|
||||
sudo cp conf/http-auth /etc/pam.d/
|
||||
sudo cp ../target/release/libpam_http.so /lib/security/pam_http.so
|
||||
|
||||
test:
|
||||
@just install
|
||||
gcc -o ../target/pam_test test.c -lpam -lpam_misc
|
||||
35
pam-http/README.md
Normal file
35
pam-http/README.md
Normal file
@@ -0,0 +1,35 @@
|
||||
pam-http
|
||||
========
|
||||
|
||||
A PAM HTTP BasicAuth module built using pam-rs
|
||||
|
||||
# Prerequisites
|
||||
|
||||
You need some libraries before you build like libpam and libssl.
|
||||
|
||||
If you're going to build on Ubuntu, just run this:
|
||||
|
||||
```
|
||||
sudo apt-get install -y build-essential libpam0g-dev libpam0g libssl-dev
|
||||
```
|
||||
|
||||
# Building
|
||||
|
||||
Just use `cargo build`.
|
||||
|
||||
# Usage
|
||||
|
||||
You need to move the build product to a folder where PAM is looking for modules.
|
||||
|
||||
If you're using Ubuntu you can move `libpam_http.so` to `/lib/security`.
|
||||
After doing so you need to make sure it has proper permissions: `sudo chmod 755 /lib/security/libpam_http.so`.
|
||||
Then you can place a configuration file in `/etc/pam.d/`. It can look something like this:
|
||||
|
||||
```
|
||||
auth sufficient libpam_http.so url=https://theserver.example.com/someendpoint
|
||||
account sufficient libpam_http.so
|
||||
```
|
||||
|
||||
Make sure the endpoint you're specifying can receive GET requests and supports
|
||||
[HTTP Basic Authentication](https://en.wikipedia.org/wiki/Basic_access_authentication#Client_side).
|
||||
If the user is authenticated successfully it should return HTTP 200.
|
||||
2
pam-http/conf/http-auth
Normal file
2
pam-http/conf/http-auth
Normal file
@@ -0,0 +1,2 @@
|
||||
auth sufficient pam_http.so url=http://localhost:3000
|
||||
account sufficient pam_http.so
|
||||
88
pam-http/src/lib.rs
Normal file
88
pam-http/src/lib.rs
Normal file
@@ -0,0 +1,88 @@
|
||||
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())
|
||||
}
|
||||
52
pam-http/test.c
Normal file
52
pam-http/test.c
Normal file
@@ -0,0 +1,52 @@
|
||||
#include <security/pam_appl.h>
|
||||
#include <security/pam_misc.h>
|
||||
#include <stdio.h>
|
||||
|
||||
const struct pam_conv conv = {
|
||||
misc_conv,
|
||||
NULL
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
pam_handle_t* pamh = NULL;
|
||||
int retval;
|
||||
const char* user = "nobody";
|
||||
|
||||
if(argc != 2) {
|
||||
printf("Usage: app [username]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
user = argv[1];
|
||||
|
||||
retval = pam_start("http-auth", user, &conv, &pamh);
|
||||
|
||||
// Are the credentials correct?
|
||||
if (retval == PAM_SUCCESS) {
|
||||
printf("Credentials accepted.\n");
|
||||
retval = pam_authenticate(pamh, 0);
|
||||
}
|
||||
|
||||
// Can the accound be used at this time?
|
||||
if (retval == PAM_SUCCESS) {
|
||||
printf("Account is valid.\n");
|
||||
retval = pam_acct_mgmt(pamh, 0);
|
||||
}
|
||||
|
||||
// Did everything work?
|
||||
if (retval == PAM_SUCCESS) {
|
||||
printf("Authenticated\n");
|
||||
} else {
|
||||
printf("Not Authenticated\n");
|
||||
}
|
||||
|
||||
// close PAM (end session)
|
||||
if (pam_end(pamh, retval) != PAM_SUCCESS) {
|
||||
pamh = NULL;
|
||||
printf("check_user: failed to release authenticator\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return retval == PAM_SUCCESS ? 0 : 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user