forked from proxmox-mirrors/proxmox
auth-api: set PAM_RHOST during pam authentication
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
8f08039e7e
commit
a228a22918
@ -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?;
|
||||
}
|
||||
|
||||
|
@ -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>;
|
||||
|
@ -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 =
|
||||
|
Loading…
Reference in New Issue
Block a user