diff --git a/src/api2.rs b/src/api2.rs index 31c9d8e7..abcba8e3 100644 --- a/src/api2.rs +++ b/src/api2.rs @@ -1,4 +1,4 @@ -mod access; +pub mod access; pub mod admin; pub mod backup; pub mod config; diff --git a/src/api2/access.rs b/src/api2/access.rs index 25b23321..6cfc4c81 100644 --- a/src/api2/access.rs +++ b/src/api2/access.rs @@ -2,7 +2,7 @@ use failure::*; use serde_json::{json, Value}; -use proxmox::api::api; +use proxmox::api::{api, RpcEnvironment}; use proxmox::api::router::{Router, SubdirMap}; use proxmox::sortable; use proxmox::{http_err, list_subdirs_api_method}; @@ -10,6 +10,9 @@ use proxmox::{http_err, list_subdirs_api_method}; use crate::tools; use crate::tools::ticket::*; use crate::auth_helpers::*; +use crate::api2::types::*; + +pub mod user; fn authenticate_user(username: &str, password: &str) -> Result<(), Error> { @@ -32,13 +35,10 @@ fn authenticate_user(username: &str, password: &str) -> Result<(), Error> { input: { properties: { username: { - type: String, - description: "User name.", - max_length: 64, + schema: PROXMOX_USER_ID_SCHEMA, }, password: { - type: String, - description: "The secret password. This can also be a valid ticket.", + schema: PASSWORD_SCHEMA, }, }, }, @@ -87,12 +87,57 @@ fn create_ticket(username: String, password: String) -> Result { } } +#[api( + input: { + properties: { + userid: { + schema: PROXMOX_USER_ID_SCHEMA, + }, + password: { + schema: PASSWORD_SCHEMA, + }, + }, + }, +)] +/// Change user password +/// +/// Each user is allowed to change his own password. Superuser +/// can change all passwords. +fn change_password( + userid: String, + password: String, + rpcenv: &mut dyn RpcEnvironment, +) -> Result { + + let current_user = rpcenv.get_user() + .ok_or_else(|| format_err!("unknown user"))?; + + let mut allowed = userid == current_user; + + if userid == "root@pam" { allowed = true; } + + if !allowed { + bail!("you are not authorized to change the password."); + } + + let (username, realm) = crate::auth::parse_userid(&userid)?; + let authenticator = crate::auth::lookup_authenticator(&realm)?; + authenticator.store_password(&username, &password)?; + + Ok(Value::Null) +} + #[sortable] const SUBDIRS: SubdirMap = &[ + ( + "password", &Router::new() + .put(&API_METHOD_CHANGE_PASSWORD) + ), ( "ticket", &Router::new() .post(&API_METHOD_CREATE_TICKET) - ) + ), + ("users", &user::ROUTER), ]; pub const ROUTER: Router = Router::new() diff --git a/src/api2/config/user.rs b/src/api2/access/user.rs similarity index 99% rename from src/api2/config/user.rs rename to src/api2/access/user.rs index d59788f2..6a4bc57c 100644 --- a/src/api2/config/user.rs +++ b/src/api2/access/user.rs @@ -140,7 +140,7 @@ pub fn create_user(userid: String, password: Option, param: Value) -> Re userid: { schema: PROXMOX_USER_ID_SCHEMA, }, - }, + }, }, returns: { description: "The user configuration (with config digest).", diff --git a/src/api2/config.rs b/src/api2/config.rs index cb114688..79db82da 100644 --- a/src/api2/config.rs +++ b/src/api2/config.rs @@ -3,12 +3,10 @@ use proxmox::list_subdirs_api_method; pub mod datastore; pub mod remote; -pub mod user; const SUBDIRS: SubdirMap = &[ ("datastore", &datastore::ROUTER), ("remote", &remote::ROUTER), - ("user", &user::ROUTER), ]; pub const ROUTER: Router = Router::new() diff --git a/src/api2/types.rs b/src/api2/types.rs index 806ba4ba..12ee8c1c 100644 --- a/src/api2/types.rs +++ b/src/api2/types.rs @@ -91,6 +91,17 @@ pub const PASSWORD_FORMAT: ApiStringFormat = ApiStringFormat::Pattern(&PASSWORD_REGEX); +pub const PASSWORD_SCHEMA: Schema = StringSchema::new("Password.") + .format(&PASSWORD_FORMAT) + .min_length(1) + .max_length(64) + .schema(); + +pub const PBS_PASSWORD_SCHEMA: Schema = StringSchema::new("User Password.") + .format(&PASSWORD_FORMAT) + .min_length(5) + .max_length(64) + .schema(); pub const CERT_FINGERPRINT_SHA256_SCHEMA: Schema = StringSchema::new( "X509 certificate fingerprint (sha256)." diff --git a/src/bin/proxmox-backup-manager.rs b/src/bin/proxmox-backup-manager.rs index 3424241a..c7c2f51a 100644 --- a/src/bin/proxmox-backup-manager.rs +++ b/src/bin/proxmox-backup-manager.rs @@ -125,7 +125,7 @@ fn list_users(param: Value, rpcenv: &mut dyn RpcEnvironment) -> Result (handler)(param, info, rpcenv)?, _ => unreachable!(), @@ -152,18 +152,18 @@ fn user_commands() -> CommandLineInterface { .insert( "create", // fixme: howto handle password parameter? - CliCommand::new(&api2::config::user::API_METHOD_CREATE_USER) + CliCommand::new(&api2::access::user::API_METHOD_CREATE_USER) .arg_param(&["userid"]) ) .insert( "update", - CliCommand::new(&api2::config::user::API_METHOD_UPDATE_USER) + CliCommand::new(&api2::access::user::API_METHOD_UPDATE_USER) .arg_param(&["userid"]) .completion_cb("userid", config::user::complete_user_name) ) .insert( "remove", - CliCommand::new(&api2::config::user::API_METHOD_DELETE_USER) + CliCommand::new(&api2::access::user::API_METHOD_DELETE_USER) .arg_param(&["userid"]) .completion_cb("userid", config::user::complete_user_name) );