1 use anyhow
::{bail, Error}
;
4 use proxmox
::api
::{api, ApiMethod, Router, RpcEnvironment, Permission}
;
5 use proxmox
::api
::schema
::{Schema, StringSchema}
;
7 use crate::api2
::types
::*;
8 use crate::config
::user
;
9 use crate::config
::acl
::{PRIV_SYS_AUDIT, PRIV_PERMISSIONS_MODIFY}
;
11 pub const PBS_PASSWORD_SCHEMA
: Schema
= StringSchema
::new("User Password.")
12 .format(&PASSWORD_FORMAT
)
22 description
: "List users (with config digest).",
26 description
: "User configuration (without password).",
30 permission
: &Permission
::Privilege(&["access", "users"], PRIV_SYS_AUDIT
, false),
37 mut rpcenv
: &mut dyn RpcEnvironment
,
38 ) -> Result
<Vec
<user
::User
>, Error
> {
40 let (config
, digest
) = user
::config()?
;
42 let list
= config
.convert_to_typed_array("user")?
;
44 rpcenv
["digest"] = proxmox
::tools
::digest_to_hex(&digest
).into();
54 schema
: PROXMOX_USER_ID_SCHEMA
,
57 schema
: SINGLE_LINE_COMMENT_SCHEMA
,
61 schema
: PBS_PASSWORD_SCHEMA
,
65 schema
: user
::ENABLE_USER_SCHEMA
,
69 schema
: user
::EXPIRE_USER_SCHEMA
,
73 schema
: user
::FIRST_NAME_SCHEMA
,
77 schema
: user
::LAST_NAME_SCHEMA
,
81 schema
: user
::EMAIL_SCHEMA
,
87 permission
: &Permission
::Privilege(&["access", "users"], PRIV_PERMISSIONS_MODIFY
, false),
91 pub fn create_user(password
: Option
<String
>, param
: Value
) -> Result
<(), Error
> {
93 let _lock
= crate::tools
::open_file_locked(user
::USER_CFG_LOCKFILE
, std
::time
::Duration
::new(10, 0))?
;
95 let user
: user
::User
= serde_json
::from_value(param
)?
;
97 let (mut config
, _digest
) = user
::config()?
;
99 if let Some(_
) = config
.sections
.get(&user
.userid
) {
100 bail
!("user '{}' already exists.", user
.userid
);
103 let (username
, realm
) = crate::auth
::parse_userid(&user
.userid
)?
;
104 let authenticator
= crate::auth
::lookup_authenticator(&realm
)?
;
106 config
.set_data(&user
.userid
, "user", &user
)?
;
108 user
::save_config(&config
)?
;
110 if let Some(password
) = password
{
111 authenticator
.store_password(&username
, &password
)?
;
121 schema
: PROXMOX_USER_ID_SCHEMA
,
126 description
: "The user configuration (with config digest).",
130 permission
: &Permission
::Privilege(&["access", "users"], PRIV_SYS_AUDIT
, false),
133 /// Read user configuration data.
134 pub fn read_user(userid
: String
, mut rpcenv
: &mut dyn RpcEnvironment
) -> Result
<user
::User
, Error
> {
135 let (config
, digest
) = user
::config()?
;
136 let user
= config
.lookup("user", &userid
)?
;
137 rpcenv
["digest"] = proxmox
::tools
::digest_to_hex(&digest
).into();
146 schema
: PROXMOX_USER_ID_SCHEMA
,
150 schema
: SINGLE_LINE_COMMENT_SCHEMA
,
153 schema
: PBS_PASSWORD_SCHEMA
,
157 schema
: user
::ENABLE_USER_SCHEMA
,
161 schema
: user
::EXPIRE_USER_SCHEMA
,
165 schema
: user
::FIRST_NAME_SCHEMA
,
169 schema
: user
::LAST_NAME_SCHEMA
,
173 schema
: user
::EMAIL_SCHEMA
,
178 schema
: PROXMOX_CONFIG_DIGEST_SCHEMA
,
183 permission
: &Permission
::Privilege(&["access", "users"], PRIV_PERMISSIONS_MODIFY
, false),
186 /// Update user configuration.
189 comment
: Option
<String
>,
190 enable
: Option
<bool
>,
192 password
: Option
<String
>,
193 firstname
: Option
<String
>,
194 lastname
: Option
<String
>,
195 email
: Option
<String
>,
196 digest
: Option
<String
>,
197 ) -> Result
<(), Error
> {
199 let _lock
= crate::tools
::open_file_locked(user
::USER_CFG_LOCKFILE
, std
::time
::Duration
::new(10, 0))?
;
201 let (mut config
, expected_digest
) = user
::config()?
;
203 if let Some(ref digest
) = digest
{
204 let digest
= proxmox
::tools
::hex_to_digest(digest
)?
;
205 crate::tools
::detect_modified_configuration_file(&digest
, &expected_digest
)?
;
208 let mut data
: user
::User
= config
.lookup("user", &userid
)?
;
210 if let Some(comment
) = comment
{
211 let comment
= comment
.trim().to_string();
212 if comment
.is_empty() {
215 data
.comment
= Some(comment
);
219 if let Some(enable
) = enable
{
220 data
.enable
= if enable { None }
else { Some(false) }
;
223 if let Some(expire
) = expire
{
224 data
.expire
= if expire
> 0 { Some(expire) }
else { None }
;
227 if let Some(password
) = password
{
228 let (username
, realm
) = crate::auth
::parse_userid(&userid
)?
;
229 let authenticator
= crate::auth
::lookup_authenticator(&realm
)?
;
230 authenticator
.store_password(&username
, &password
)?
;
233 if let Some(firstname
) = firstname
{
234 data
.firstname
= if firstname
.is_empty() { None }
else { Some(firstname) }
;
237 if let Some(lastname
) = lastname
{
238 data
.lastname
= if lastname
.is_empty() { None }
else { Some(lastname) }
;
240 if let Some(email
) = email
{
241 data
.email
= if email
.is_empty() { None }
else { Some(email) }
;
244 config
.set_data(&userid
, "user", &data
)?
;
246 user
::save_config(&config
)?
;
256 schema
: PROXMOX_USER_ID_SCHEMA
,
260 schema
: PROXMOX_CONFIG_DIGEST_SCHEMA
,
265 permission
: &Permission
::Privilege(&["access", "users"], PRIV_PERMISSIONS_MODIFY
, false),
268 /// Remove a user from the configuration file.
269 pub fn delete_user(userid
: String
, digest
: Option
<String
>) -> Result
<(), Error
> {
271 let _lock
= crate::tools
::open_file_locked(user
::USER_CFG_LOCKFILE
, std
::time
::Duration
::new(10, 0))?
;
273 let (mut config
, expected_digest
) = user
::config()?
;
275 if let Some(ref digest
) = digest
{
276 let digest
= proxmox
::tools
::hex_to_digest(digest
)?
;
277 crate::tools
::detect_modified_configuration_file(&digest
, &expected_digest
)?
;
280 match config
.sections
.get(&userid
) {
281 Some(_
) => { config.sections.remove(&userid); }
,
282 None
=> bail
!("user '{}' does not exist.", userid
),
285 user
::save_config(&config
)?
;
290 const ITEM_ROUTER
: Router
= Router
::new()
291 .get(&API_METHOD_READ_USER
)
292 .put(&API_METHOD_UPDATE_USER
)
293 .delete(&API_METHOD_DELETE_USER
);
295 pub const ROUTER
: Router
= Router
::new()
296 .get(&API_METHOD_LIST_USERS
)
297 .post(&API_METHOD_CREATE_USER
)
298 .match_all("userid", &ITEM_ROUTER
);