auth-api: set PAM_RHOST during pam authentication

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2023-06-13 09:23:18 +02:00
parent 8f08039e7e
commit a228a22918
3 changed files with 49 additions and 9 deletions

View File

@ -3,6 +3,7 @@
use anyhow::{bail, format_err, Error};
use serde_json::{json, Value};
use proxmox_rest_server::RestEnvironment;
use proxmox_router::{http_err, Permission, RpcEnvironment};
use proxmox_schema::{api, api_types::PASSWORD_SCHEMA};
use proxmox_tfa::api::TfaChallenge;
@ -90,14 +91,12 @@ pub async fn create_ticket(
tfa_challenge: Option<String>,
rpcenv: &mut dyn RpcEnvironment,
) -> Result<Value, Error> {
use proxmox_rest_server::RestEnvironment;
let env: &RestEnvironment = rpcenv
.as_any()
.downcast_ref::<RestEnvironment>()
.ok_or_else(|| format_err!("detected wrong RpcEnvironment type"))?;
match authenticate_user(&username, &password, path, privs, port, tfa_challenge).await {
match authenticate_user(&username, &password, path, privs, port, tfa_challenge, env).await {
Ok(AuthResult::Success) => Ok(json!({ "username": username })),
Ok(AuthResult::CreateTicket) => {
let auth_context = auth_context()?;
@ -139,6 +138,7 @@ async fn authenticate_user(
privs: Option<String>,
port: Option<u16>,
tfa_challenge: Option<String>,
rpcenv: &RestEnvironment,
) -> Result<AuthResult, Error> {
let auth_context = auth_context()?;
let prefix = auth_context.auth_prefix();
@ -170,12 +170,14 @@ async fn authenticate_user(
}
}
let client_ip = rpcenv.get_client_ip().map(|sa| sa.ip());
#[allow(clippy::let_unit_value)]
{
let _: () = auth_context
.lookup_realm(userid.realm())
.ok_or_else(|| format_err!("unknown realm {:?}", userid.realm().as_str()))?
.authenticate_user(userid.name(), password)
.authenticate_user(userid.name(), password, client_ip.as_ref())
.await?;
}

View File

@ -1,4 +1,5 @@
use std::future::Future;
use std::net::IpAddr;
use std::pin::Pin;
use std::sync::Mutex;
@ -27,10 +28,16 @@ pub trait Authenticator {
&'a self,
username: &'a UsernameRef,
password: &'a str,
client_ip: Option<&'a IpAddr>,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'a>>;
/// Change a user's password.
fn store_password(&self, username: &UsernameRef, password: &str) -> Result<(), Error>;
fn store_password(
&self,
username: &UsernameRef,
password: &str,
client_ip: Option<&IpAddr>,
) -> Result<(), Error>;
/// Remove a user.
fn remove_password(&self, username: &UsernameRef) -> Result<(), Error>;

View File

@ -1,9 +1,12 @@
use std::ffi::{c_int, c_void, CStr};
use std::ffi::{c_int, c_void, CStr, CString};
use std::future::Future;
use std::net::IpAddr;
use std::pin::Pin;
use anyhow::{bail, Error};
use pam_sys::types::{PamHandle, PamMessage, PamMessageStyle, PamResponse, PamReturnCode};
use anyhow::{bail, format_err, Error};
use pam_sys::types::{
PamHandle, PamItemType, PamMessage, PamMessageStyle, PamResponse, PamReturnCode,
};
use crate::types::UsernameRef;
@ -23,6 +26,7 @@ impl crate::api::Authenticator for Pam {
&'a self,
username: &'a UsernameRef,
password: &'a str,
client_ip: Option<&'a IpAddr>,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'a>> {
Box::pin(async move {
let mut password_conv = PasswordConv {
@ -46,6 +50,17 @@ impl crate::api::Authenticator for Pam {
result: PamReturnCode::SUCCESS,
};
if let Some(ip) = client_ip {
let ip = ip.to_string();
let ip = CString::new(ip).map_err(|_| format_err!("nul-byte in client ip"))?;
let ip = unsafe { &*(ip.as_ptr() as *const libc::c_void) };
let err = pam_sys::wrapped::set_item(handle.handle, PamItemType::RHOST, ip);
if err != PamReturnCode::SUCCESS {
bail!("error setting PAM_RHOST - {err}");
}
}
handle.result =
pam_sys::wrapped::authenticate(handle.handle, pam_sys::types::PamFlag::NONE);
if handle.result != PamReturnCode::SUCCESS {
@ -56,7 +71,12 @@ impl crate::api::Authenticator for Pam {
})
}
fn store_password(&self, username: &UsernameRef, password: &str) -> Result<(), Error> {
fn store_password(
&self,
username: &UsernameRef,
password: &str,
client_ip: Option<&IpAddr>,
) -> Result<(), Error> {
let mut password_conv = PasswordConv {
login: username.as_str(),
password,
@ -78,6 +98,17 @@ impl crate::api::Authenticator for Pam {
result: PamReturnCode::SUCCESS,
};
if let Some(ip) = client_ip {
let ip = ip.to_string();
let ip = CString::new(ip).map_err(|_| format_err!("nul-byte in client ip"))?;
let ip = unsafe { &*(ip.as_ptr() as *const libc::c_void) };
let err = pam_sys::wrapped::set_item(handle.handle, PamItemType::RHOST, ip);
if err != PamReturnCode::SUCCESS {
bail!("error setting PAM_RHOST - {err}");
}
}
/*
* we assume we're root and don't need to authenticate
handle.result =