api: access: add update support for built-in PAM realm

For the built-in PAM authentication realm, the comment and whether it
should be the default login realm can be updated. Add the required API
plumbing for it.

Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
Reviewed-by: Lukas Wagner <l.wagner@proxmox.com>
Tested-by: Lukas Wagner <l.wagner@proxmox.com>
This commit is contained in:
Christoph Heiss 2025-03-21 14:45:36 +01:00 committed by Thomas Lamprecht
parent a738d2bcc9
commit 029654a61d
2 changed files with 132 additions and 0 deletions

View File

@ -5,10 +5,12 @@ use proxmox_sortable_macro::sortable;
pub mod ad;
pub mod ldap;
pub mod openid;
pub mod pam;
pub mod tfa;
#[sortable]
const SUBDIRS: SubdirMap = &sorted!([
("pam", &pam::ROUTER),
("ad", &ad::ROUTER),
("ldap", &ldap::ROUTER),
("openid", &openid::ROUTER),

View File

@ -0,0 +1,130 @@
use ::serde::{Deserialize, Serialize};
use anyhow::Error;
use hex::FromHex;
use proxmox_router::{Permission, Router, RpcEnvironment};
use proxmox_schema::api;
use pbs_api_types::{
PamRealmConfig, PamRealmConfigUpdater, PRIV_REALM_ALLOCATE, PRIV_SYS_AUDIT,
PROXMOX_CONFIG_DIGEST_SCHEMA,
};
use pbs_config::domains;
#[api(
returns: {
type: PamRealmConfig,
},
access: {
permission: &Permission::Privilege(&["access", "domains"], PRIV_SYS_AUDIT, false),
},
)]
/// Read the PAM realm configuration
pub fn read_pam_realm(rpcenv: &mut dyn RpcEnvironment) -> Result<PamRealmConfig, Error> {
let (domains, digest) = domains::config()?;
let config = domains.lookup("pam", "pam")?;
rpcenv["digest"] = hex::encode(digest).into();
Ok(config)
}
#[api]
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
/// Deletable property name
pub enum DeletableProperty {
/// Delete the comment property.
Comment,
/// Delete the default property.
Default,
}
#[api(
protected: true,
input: {
properties: {
update: {
type: PamRealmConfigUpdater,
flatten: true,
},
delete: {
description: "List of properties to delete.",
type: Array,
optional: true,
items: {
type: DeletableProperty,
}
},
digest: {
optional: true,
schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
},
},
},
returns: {
type: PamRealmConfig,
},
access: {
permission: &Permission::Privilege(&["access", "domains"], PRIV_REALM_ALLOCATE, false),
},
)]
/// Update the PAM realm configuration
pub fn update_pam_realm(
update: PamRealmConfigUpdater,
delete: Option<Vec<DeletableProperty>>,
digest: Option<String>,
_rpcenv: &mut dyn RpcEnvironment,
) -> Result<(), Error> {
let _lock = domains::lock_config()?;
let (mut domains, expected_digest) = domains::config()?;
if let Some(ref digest) = digest {
let digest = <[u8; 32]>::from_hex(digest)?;
crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
}
let mut config: PamRealmConfig = domains.lookup("pam", "pam")?;
if let Some(delete) = delete {
for delete_prop in delete {
match delete_prop {
DeletableProperty::Comment => {
config.comment = None;
}
DeletableProperty::Default => {
config.default = None;
}
}
}
}
if let Some(comment) = update.comment {
let comment = comment.trim().to_string();
if comment.is_empty() {
config.comment = None;
} else {
config.comment = Some(comment);
}
}
if let Some(true) = update.default {
pbs_config::domains::unset_default_realm(&mut domains)?;
config.default = Some(true);
} else {
config.default = None;
}
domains.set_data("pam", "pam", &config)?;
domains::save_config(&domains)?;
Ok(())
}
pub const ROUTER: Router = Router::new()
.get(&API_METHOD_READ_PAM_REALM)
.put(&API_METHOD_UPDATE_PAM_REALM);