use proxmox::api::{api, ApiMethod, Router, RpcEnvironment, Permission};
use proxmox::api::schema::{Schema, StringSchema};
+use proxmox::tools::fs::open_file_locked;
use crate::api2::types::*;
use crate::config::user;
use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_PERMISSIONS_MODIFY};
+use crate::config::cached_user_info::CachedUserInfo;
pub const PBS_PASSWORD_SCHEMA: Schema = StringSchema::new("User Password.")
.format(&PASSWORD_FORMAT)
returns: {
description: "List users (with config digest).",
type: Array,
- items: {
- type: user::User,
- description: "User configuration (without password).",
- },
+ items: { type: user::User },
},
access: {
- permission: &Permission::Privilege(&["access", "users"], PRIV_SYS_AUDIT, false),
+ permission: &Permission::Anybody,
+ description: "Returns all or just the logged-in user, depending on privileges.",
},
)]
-/// List all users
+/// List users
pub fn list_users(
_param: Value,
_info: &ApiMethod,
let (config, digest) = user::config()?;
- let list = config.convert_to_typed_array("user")?;
+ let userid: Userid = rpcenv.get_user().unwrap().parse()?;
+ let user_info = CachedUserInfo::new()?;
+
+ let top_level_privs = user_info.lookup_privs(&userid, &["access", "users"]);
+ let top_level_allowed = (top_level_privs & PRIV_SYS_AUDIT) != 0;
+
+ let filter_by_privs = |user: &user::User| {
+ top_level_allowed || user.userid == userid
+ };
+
+ let list:Vec<user::User> = config.convert_to_typed_array("user")?;
rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into();
- Ok(list)
+ Ok(list.into_iter().filter(filter_by_privs).collect())
}
#[api(
input: {
properties: {
userid: {
- schema: PROXMOX_USER_ID_SCHEMA,
+ type: Userid,
},
comment: {
schema: SINGLE_LINE_COMMENT_SCHEMA,
/// Create new user.
pub fn create_user(password: Option<String>, param: Value) -> Result<(), Error> {
- let _lock = crate::tools::open_file_locked(user::USER_CFG_LOCKFILE, std::time::Duration::new(10, 0))?;
+ let _lock = open_file_locked(user::USER_CFG_LOCKFILE, std::time::Duration::new(10, 0))?;
let user: user::User = serde_json::from_value(param)?;
let (mut config, _digest) = user::config()?;
- if let Some(_) = config.sections.get(&user.userid) {
+ if let Some(_) = config.sections.get(user.userid.as_str()) {
bail!("user '{}' already exists.", user.userid);
}
- let (username, realm) = crate::auth::parse_userid(&user.userid)?;
- let authenticator = crate::auth::lookup_authenticator(&realm)?;
+ let authenticator = crate::auth::lookup_authenticator(&user.userid.realm())?;
- config.set_data(&user.userid, "user", &user)?;
+ config.set_data(user.userid.as_str(), "user", &user)?;
user::save_config(&config)?;
if let Some(password) = password {
- authenticator.store_password(&username, &password)?;
+ authenticator.store_password(user.userid.name(), &password)?;
}
Ok(())
input: {
properties: {
userid: {
- schema: PROXMOX_USER_ID_SCHEMA,
+ type: Userid,
},
},
},
type: user::User,
},
access: {
- permission: &Permission::Privilege(&["access", "users"], PRIV_SYS_AUDIT, false),
+ permission: &Permission::Or(&[
+ &Permission::Privilege(&["access", "users"], PRIV_SYS_AUDIT, false),
+ &Permission::UserParam("userid"),
+ ]),
},
)]
/// Read user configuration data.
-pub fn read_user(userid: String, mut rpcenv: &mut dyn RpcEnvironment) -> Result<user::User, Error> {
+pub fn read_user(userid: Userid, mut rpcenv: &mut dyn RpcEnvironment) -> Result<user::User, Error> {
let (config, digest) = user::config()?;
- let user = config.lookup("user", &userid)?;
+ let user = config.lookup("user", userid.as_str())?;
rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into();
Ok(user)
}
input: {
properties: {
userid: {
- schema: PROXMOX_USER_ID_SCHEMA,
+ type: Userid,
},
comment: {
optional: true,
},
},
access: {
- permission: &Permission::Privilege(&["access", "users"], PRIV_PERMISSIONS_MODIFY, false),
+ permission: &Permission::Or(&[
+ &Permission::Privilege(&["access", "users"], PRIV_PERMISSIONS_MODIFY, false),
+ &Permission::UserParam("userid"),
+ ]),
},
)]
/// Update user configuration.
pub fn update_user(
- userid: String,
+ userid: Userid,
comment: Option<String>,
enable: Option<bool>,
expire: Option<i64>,
digest: Option<String>,
) -> Result<(), Error> {
- let _lock = crate::tools::open_file_locked(user::USER_CFG_LOCKFILE, std::time::Duration::new(10, 0))?;
+ let _lock = open_file_locked(user::USER_CFG_LOCKFILE, std::time::Duration::new(10, 0))?;
let (mut config, expected_digest) = user::config()?;
crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
}
- let mut data: user::User = config.lookup("user", &userid)?;
+ let mut data: user::User = config.lookup("user", userid.as_str())?;
if let Some(comment) = comment {
let comment = comment.trim().to_string();
}
if let Some(password) = password {
- let (username, realm) = crate::auth::parse_userid(&userid)?;
- let authenticator = crate::auth::lookup_authenticator(&realm)?;
- authenticator.store_password(&username, &password)?;
+ let authenticator = crate::auth::lookup_authenticator(userid.realm())?;
+ authenticator.store_password(userid.name(), &password)?;
}
if let Some(firstname) = firstname {
data.email = if email.is_empty() { None } else { Some(email) };
}
- config.set_data(&userid, "user", &data)?;
+ config.set_data(userid.as_str(), "user", &data)?;
user::save_config(&config)?;
input: {
properties: {
userid: {
- schema: PROXMOX_USER_ID_SCHEMA,
+ type: Userid,
},
digest: {
optional: true,
},
},
access: {
- permission: &Permission::Privilege(&["access", "users"], PRIV_PERMISSIONS_MODIFY, false),
+ permission: &Permission::Or(&[
+ &Permission::Privilege(&["access", "users"], PRIV_PERMISSIONS_MODIFY, false),
+ &Permission::UserParam("userid"),
+ ]),
},
)]
/// Remove a user from the configuration file.
-pub fn delete_user(userid: String, digest: Option<String>) -> Result<(), Error> {
+pub fn delete_user(userid: Userid, digest: Option<String>) -> Result<(), Error> {
- let _lock = crate::tools::open_file_locked(user::USER_CFG_LOCKFILE, std::time::Duration::new(10, 0))?;
+ let _lock = open_file_locked(user::USER_CFG_LOCKFILE, std::time::Duration::new(10, 0))?;
let (mut config, expected_digest) = user::config()?;
crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
}
- match config.sections.get(&userid) {
- Some(_) => { config.sections.remove(&userid); },
+ match config.sections.get(userid.as_str()) {
+ Some(_) => { config.sections.remove(userid.as_str()); },
None => bail!("user '{}' does not exist.", userid),
}