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).",
24 items
: { type: user::User }
,
27 permission
: &Permission
::Privilege(&["access", "users"], PRIV_SYS_AUDIT
, false),
34 mut rpcenv
: &mut dyn RpcEnvironment
,
35 ) -> Result
<Vec
<user
::User
>, Error
> {
37 let (config
, digest
) = user
::config()?
;
39 let list
= config
.convert_to_typed_array("user")?
;
41 rpcenv
["digest"] = proxmox
::tools
::digest_to_hex(&digest
).into();
51 schema
: PROXMOX_USER_ID_SCHEMA
,
54 schema
: SINGLE_LINE_COMMENT_SCHEMA
,
58 schema
: PBS_PASSWORD_SCHEMA
,
62 schema
: user
::ENABLE_USER_SCHEMA
,
66 schema
: user
::EXPIRE_USER_SCHEMA
,
70 schema
: user
::FIRST_NAME_SCHEMA
,
74 schema
: user
::LAST_NAME_SCHEMA
,
78 schema
: user
::EMAIL_SCHEMA
,
84 permission
: &Permission
::Privilege(&["access", "users"], PRIV_PERMISSIONS_MODIFY
, false),
88 pub fn create_user(password
: Option
<String
>, param
: Value
) -> Result
<(), Error
> {
90 let _lock
= crate::tools
::open_file_locked(user
::USER_CFG_LOCKFILE
, std
::time
::Duration
::new(10, 0))?
;
92 let user
: user
::User
= serde_json
::from_value(param
)?
;
94 let (mut config
, _digest
) = user
::config()?
;
96 if let Some(_
) = config
.sections
.get(&user
.userid
) {
97 bail
!("user '{}' already exists.", user
.userid
);
100 let (username
, realm
) = crate::auth
::parse_userid(&user
.userid
)?
;
101 let authenticator
= crate::auth
::lookup_authenticator(&realm
)?
;
103 config
.set_data(&user
.userid
, "user", &user
)?
;
105 user
::save_config(&config
)?
;
107 if let Some(password
) = password
{
108 authenticator
.store_password(&username
, &password
)?
;
118 schema
: PROXMOX_USER_ID_SCHEMA
,
123 description
: "The user configuration (with config digest).",
127 permission
: &Permission
::Privilege(&["access", "users"], PRIV_SYS_AUDIT
, false),
130 /// Read user configuration data.
131 pub fn read_user(userid
: String
, mut rpcenv
: &mut dyn RpcEnvironment
) -> Result
<user
::User
, Error
> {
132 let (config
, digest
) = user
::config()?
;
133 let user
= config
.lookup("user", &userid
)?
;
134 rpcenv
["digest"] = proxmox
::tools
::digest_to_hex(&digest
).into();
143 schema
: PROXMOX_USER_ID_SCHEMA
,
147 schema
: SINGLE_LINE_COMMENT_SCHEMA
,
150 schema
: PBS_PASSWORD_SCHEMA
,
154 schema
: user
::ENABLE_USER_SCHEMA
,
158 schema
: user
::EXPIRE_USER_SCHEMA
,
162 schema
: user
::FIRST_NAME_SCHEMA
,
166 schema
: user
::LAST_NAME_SCHEMA
,
170 schema
: user
::EMAIL_SCHEMA
,
175 schema
: PROXMOX_CONFIG_DIGEST_SCHEMA
,
180 permission
: &Permission
::Privilege(&["access", "users"], PRIV_PERMISSIONS_MODIFY
, false),
183 /// Update user configuration.
186 comment
: Option
<String
>,
187 enable
: Option
<bool
>,
189 password
: Option
<String
>,
190 firstname
: Option
<String
>,
191 lastname
: Option
<String
>,
192 email
: Option
<String
>,
193 digest
: Option
<String
>,
194 ) -> Result
<(), Error
> {
196 let _lock
= crate::tools
::open_file_locked(user
::USER_CFG_LOCKFILE
, std
::time
::Duration
::new(10, 0))?
;
198 let (mut config
, expected_digest
) = user
::config()?
;
200 if let Some(ref digest
) = digest
{
201 let digest
= proxmox
::tools
::hex_to_digest(digest
)?
;
202 crate::tools
::detect_modified_configuration_file(&digest
, &expected_digest
)?
;
205 let mut data
: user
::User
= config
.lookup("user", &userid
)?
;
207 if let Some(comment
) = comment
{
208 let comment
= comment
.trim().to_string();
209 if comment
.is_empty() {
212 data
.comment
= Some(comment
);
216 if let Some(enable
) = enable
{
217 data
.enable
= if enable { None }
else { Some(false) }
;
220 if let Some(expire
) = expire
{
221 data
.expire
= if expire
> 0 { Some(expire) }
else { None }
;
224 if let Some(password
) = password
{
225 let (username
, realm
) = crate::auth
::parse_userid(&userid
)?
;
226 let authenticator
= crate::auth
::lookup_authenticator(&realm
)?
;
227 authenticator
.store_password(&username
, &password
)?
;
230 if let Some(firstname
) = firstname
{
231 data
.firstname
= if firstname
.is_empty() { None }
else { Some(firstname) }
;
234 if let Some(lastname
) = lastname
{
235 data
.lastname
= if lastname
.is_empty() { None }
else { Some(lastname) }
;
237 if let Some(email
) = email
{
238 data
.email
= if email
.is_empty() { None }
else { Some(email) }
;
241 config
.set_data(&userid
, "user", &data
)?
;
243 user
::save_config(&config
)?
;
253 schema
: PROXMOX_USER_ID_SCHEMA
,
257 schema
: PROXMOX_CONFIG_DIGEST_SCHEMA
,
262 permission
: &Permission
::Privilege(&["access", "users"], PRIV_PERMISSIONS_MODIFY
, false),
265 /// Remove a user from the configuration file.
266 pub fn delete_user(userid
: String
, digest
: Option
<String
>) -> Result
<(), Error
> {
268 let _lock
= crate::tools
::open_file_locked(user
::USER_CFG_LOCKFILE
, std
::time
::Duration
::new(10, 0))?
;
270 let (mut config
, expected_digest
) = user
::config()?
;
272 if let Some(ref digest
) = digest
{
273 let digest
= proxmox
::tools
::hex_to_digest(digest
)?
;
274 crate::tools
::detect_modified_configuration_file(&digest
, &expected_digest
)?
;
277 match config
.sections
.get(&userid
) {
278 Some(_
) => { config.sections.remove(&userid); }
,
279 None
=> bail
!("user '{}' does not exist.", userid
),
282 user
::save_config(&config
)?
;
287 const ITEM_ROUTER
: Router
= Router
::new()
288 .get(&API_METHOD_READ_USER
)
289 .put(&API_METHOD_UPDATE_USER
)
290 .delete(&API_METHOD_DELETE_USER
);
292 pub const ROUTER
: Router
= Router
::new()
293 .get(&API_METHOD_LIST_USERS
)
294 .post(&API_METHOD_CREATE_USER
)
295 .match_all("userid", &ITEM_ROUTER
);