X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=src%2Fapi2%2Faccess%2Fuser.rs;h=432a48e1239bd32abf4c7ac6d4e44b6a620d8a68;hb=be3bd0f90b39f06e036ba32b1e6b9ba25269ed7c;hp=6a4bc57ccce46e689c3943a58b45f96c82064279;hpb=685e13347e984dfe9ad82401ce88bc1c66b12642;p=proxmox-backup.git diff --git a/src/api2/access/user.rs b/src/api2/access/user.rs index 6a4bc57c..432a48e1 100644 --- a/src/api2/access/user.rs +++ b/src/api2/access/user.rs @@ -1,11 +1,14 @@ -use failure::*; +use anyhow::{bail, Error}; use serde_json::Value; -use proxmox::api::{api, ApiMethod, Router, RpcEnvironment}; +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) @@ -20,53 +23,37 @@ pub const PBS_PASSWORD_SCHEMA: Schema = StringSchema::new("User Password.") returns: { description: "List users (with config digest).", type: Array, - items: { - type: Object, - description: "User configuration (without password).", - properties: { - userid: { - schema: PROXMOX_USER_ID_SCHEMA, - }, - comment: { - schema: SINGLE_LINE_COMMENT_SCHEMA, - optional: true, - }, - enable: { - schema: user::ENABLE_USER_SCHEMA, - optional: true, - }, - expire: { - schema: user::EXPIRE_USER_SCHEMA, - optional: true, - }, - firstname: { - schema: user::FIRST_NAME_SCHEMA, - optional: true, - }, - lastname: { - schema: user::LAST_NAME_SCHEMA, - optional: true, - }, - email: { - schema: user::EMAIL_SCHEMA, - optional: true, - }, - }, - }, + items: { type: user::User }, + }, + access: { + 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, - _rpcenv: &mut dyn RpcEnvironment, -) -> Result { + mut rpcenv: &mut dyn RpcEnvironment, +) -> Result, Error> { let (config, digest) = user::config()?; - let value = config.convert_to_array("userid", Some(&digest), &[]); + 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 = config.convert_to_typed_array("user")?; - Ok(value.into()) + rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into(); + + Ok(list.into_iter().filter(filter_by_privs).collect()) } #[api( @@ -74,7 +61,7 @@ pub fn list_users( input: { properties: { userid: { - schema: PROXMOX_USER_ID_SCHEMA, + type: Userid, }, comment: { schema: SINGLE_LINE_COMMENT_SCHEMA, @@ -106,29 +93,31 @@ pub fn list_users( }, }, }, + access: { + permission: &Permission::Privilege(&["access", "users"], PRIV_PERMISSIONS_MODIFY, false), + }, )] /// Create new user. -pub fn create_user(userid: String, password: Option, param: Value) -> Result<(), Error> { +pub fn create_user(password: Option, 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.clone())?; + let user: user::User = serde_json::from_value(param)?; let (mut config, _digest) = user::config()?; - if let Some(_) = config.sections.get(&userid) { - bail!("user '{}' already exists.", userid); + if let Some(_) = config.sections.get(user.userid.as_str()) { + bail!("user '{}' already exists.", user.userid); } - let (username, realm) = crate::auth::parse_userid(&userid)?; - let authenticator = crate::auth::lookup_authenticator(&realm)?; + let authenticator = crate::auth::lookup_authenticator(&user.userid.realm())?; - config.set_data(&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(()) @@ -138,7 +127,7 @@ pub fn create_user(userid: String, password: Option, param: Value) -> Re input: { properties: { userid: { - schema: PROXMOX_USER_ID_SCHEMA, + type: Userid, }, }, }, @@ -146,14 +135,19 @@ pub fn create_user(userid: String, password: Option, param: Value) -> Re description: "The user configuration (with config digest).", type: user::User, }, + access: { + permission: &Permission::Or(&[ + &Permission::Privilege(&["access", "users"], PRIV_SYS_AUDIT, false), + &Permission::UserParam("userid"), + ]), + }, )] /// Read user configuration data. -pub fn read_user(userid: String) -> Result { +pub fn read_user(userid: Userid, mut rpcenv: &mut dyn RpcEnvironment) -> Result { let (config, digest) = user::config()?; - let mut data = config.lookup_json("user", &userid)?; - data.as_object_mut().unwrap() - .insert("digest".into(), proxmox::tools::digest_to_hex(&digest).into()); - Ok(data) + let user = config.lookup("user", userid.as_str())?; + rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into(); + Ok(user) } #[api( @@ -161,7 +155,7 @@ pub fn read_user(userid: String) -> Result { input: { properties: { userid: { - schema: PROXMOX_USER_ID_SCHEMA, + type: Userid, }, comment: { optional: true, @@ -197,10 +191,16 @@ pub fn read_user(userid: String) -> Result { }, }, }, + access: { + 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, enable: Option, expire: Option, @@ -211,7 +211,7 @@ pub fn update_user( digest: Option, ) -> 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()?; @@ -220,7 +220,7 @@ pub fn update_user( 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(); @@ -240,9 +240,8 @@ pub fn update_user( } 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 { @@ -256,7 +255,7 @@ pub fn update_user( 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)?; @@ -268,7 +267,7 @@ pub fn update_user( input: { properties: { userid: { - schema: PROXMOX_USER_ID_SCHEMA, + type: Userid, }, digest: { optional: true, @@ -276,11 +275,17 @@ pub fn update_user( }, }, }, + access: { + 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) -> Result<(), Error> { +pub fn delete_user(userid: Userid, digest: Option) -> 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()?; @@ -289,8 +294,8 @@ pub fn delete_user(userid: String, digest: Option) -> Result<(), Error> 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), }