1 use anyhow
::{bail, Error}
;
4 use proxmox
::api
::{api, ApiMethod, Router, RpcEnvironment, Permission}
;
5 use proxmox
::api
::schema
::{Schema, StringSchema}
;
6 use proxmox
::tools
::fs
::open_file_locked
;
8 use crate::api2
::types
::*;
9 use crate::config
::user
;
10 use crate::config
::acl
::{PRIV_SYS_AUDIT, PRIV_PERMISSIONS_MODIFY}
;
12 pub const PBS_PASSWORD_SCHEMA
: Schema
= StringSchema
::new("User Password.")
13 .format(&PASSWORD_FORMAT
)
23 description
: "List users (with config digest).",
25 items
: { type: user::User }
,
28 permission
: &Permission
::Privilege(&["access", "users"], PRIV_SYS_AUDIT
, false),
35 mut rpcenv
: &mut dyn RpcEnvironment
,
36 ) -> Result
<Vec
<user
::User
>, Error
> {
38 let (config
, digest
) = user
::config()?
;
40 let list
= config
.convert_to_typed_array("user")?
;
42 rpcenv
["digest"] = proxmox
::tools
::digest_to_hex(&digest
).into();
52 schema
: PROXMOX_USER_ID_SCHEMA
,
55 schema
: SINGLE_LINE_COMMENT_SCHEMA
,
59 schema
: PBS_PASSWORD_SCHEMA
,
63 schema
: user
::ENABLE_USER_SCHEMA
,
67 schema
: user
::EXPIRE_USER_SCHEMA
,
71 schema
: user
::FIRST_NAME_SCHEMA
,
75 schema
: user
::LAST_NAME_SCHEMA
,
79 schema
: user
::EMAIL_SCHEMA
,
85 permission
: &Permission
::Privilege(&["access", "users"], PRIV_PERMISSIONS_MODIFY
, false),
89 pub fn create_user(password
: Option
<String
>, param
: Value
) -> Result
<(), Error
> {
91 let _lock
= open_file_locked(user
::USER_CFG_LOCKFILE
, std
::time
::Duration
::new(10, 0))?
;
93 let user
: user
::User
= serde_json
::from_value(param
)?
;
95 let (mut config
, _digest
) = user
::config()?
;
97 if let Some(_
) = config
.sections
.get(&user
.userid
) {
98 bail
!("user '{}' already exists.", user
.userid
);
101 let (username
, realm
) = crate::auth
::parse_userid(&user
.userid
)?
;
102 let authenticator
= crate::auth
::lookup_authenticator(&realm
)?
;
104 config
.set_data(&user
.userid
, "user", &user
)?
;
106 user
::save_config(&config
)?
;
108 if let Some(password
) = password
{
109 authenticator
.store_password(&username
, &password
)?
;
119 schema
: PROXMOX_USER_ID_SCHEMA
,
124 description
: "The user configuration (with config digest).",
128 permission
: &Permission
::Privilege(&["access", "users"], PRIV_SYS_AUDIT
, false),
131 /// Read user configuration data.
132 pub fn read_user(userid
: String
, mut rpcenv
: &mut dyn RpcEnvironment
) -> Result
<user
::User
, Error
> {
133 let (config
, digest
) = user
::config()?
;
134 let user
= config
.lookup("user", &userid
)?
;
135 rpcenv
["digest"] = proxmox
::tools
::digest_to_hex(&digest
).into();
144 schema
: PROXMOX_USER_ID_SCHEMA
,
148 schema
: SINGLE_LINE_COMMENT_SCHEMA
,
151 schema
: PBS_PASSWORD_SCHEMA
,
155 schema
: user
::ENABLE_USER_SCHEMA
,
159 schema
: user
::EXPIRE_USER_SCHEMA
,
163 schema
: user
::FIRST_NAME_SCHEMA
,
167 schema
: user
::LAST_NAME_SCHEMA
,
171 schema
: user
::EMAIL_SCHEMA
,
176 schema
: PROXMOX_CONFIG_DIGEST_SCHEMA
,
181 permission
: &Permission
::Privilege(&["access", "users"], PRIV_PERMISSIONS_MODIFY
, false),
184 /// Update user configuration.
187 comment
: Option
<String
>,
188 enable
: Option
<bool
>,
190 password
: Option
<String
>,
191 firstname
: Option
<String
>,
192 lastname
: Option
<String
>,
193 email
: Option
<String
>,
194 digest
: Option
<String
>,
195 ) -> Result
<(), Error
> {
197 let _lock
= open_file_locked(user
::USER_CFG_LOCKFILE
, std
::time
::Duration
::new(10, 0))?
;
199 let (mut config
, expected_digest
) = user
::config()?
;
201 if let Some(ref digest
) = digest
{
202 let digest
= proxmox
::tools
::hex_to_digest(digest
)?
;
203 crate::tools
::detect_modified_configuration_file(&digest
, &expected_digest
)?
;
206 let mut data
: user
::User
= config
.lookup("user", &userid
)?
;
208 if let Some(comment
) = comment
{
209 let comment
= comment
.trim().to_string();
210 if comment
.is_empty() {
213 data
.comment
= Some(comment
);
217 if let Some(enable
) = enable
{
218 data
.enable
= if enable { None }
else { Some(false) }
;
221 if let Some(expire
) = expire
{
222 data
.expire
= if expire
> 0 { Some(expire) }
else { None }
;
225 if let Some(password
) = password
{
226 let (username
, realm
) = crate::auth
::parse_userid(&userid
)?
;
227 let authenticator
= crate::auth
::lookup_authenticator(&realm
)?
;
228 authenticator
.store_password(&username
, &password
)?
;
231 if let Some(firstname
) = firstname
{
232 data
.firstname
= if firstname
.is_empty() { None }
else { Some(firstname) }
;
235 if let Some(lastname
) = lastname
{
236 data
.lastname
= if lastname
.is_empty() { None }
else { Some(lastname) }
;
238 if let Some(email
) = email
{
239 data
.email
= if email
.is_empty() { None }
else { Some(email) }
;
242 config
.set_data(&userid
, "user", &data
)?
;
244 user
::save_config(&config
)?
;
254 schema
: PROXMOX_USER_ID_SCHEMA
,
258 schema
: PROXMOX_CONFIG_DIGEST_SCHEMA
,
263 permission
: &Permission
::Privilege(&["access", "users"], PRIV_PERMISSIONS_MODIFY
, false),
266 /// Remove a user from the configuration file.
267 pub fn delete_user(userid
: String
, digest
: Option
<String
>) -> Result
<(), Error
> {
269 let _lock
= open_file_locked(user
::USER_CFG_LOCKFILE
, std
::time
::Duration
::new(10, 0))?
;
271 let (mut config
, expected_digest
) = user
::config()?
;
273 if let Some(ref digest
) = digest
{
274 let digest
= proxmox
::tools
::hex_to_digest(digest
)?
;
275 crate::tools
::detect_modified_configuration_file(&digest
, &expected_digest
)?
;
278 match config
.sections
.get(&userid
) {
279 Some(_
) => { config.sections.remove(&userid); }
,
280 None
=> bail
!("user '{}' does not exist.", userid
),
283 user
::save_config(&config
)?
;
288 const ITEM_ROUTER
: Router
= Router
::new()
289 .get(&API_METHOD_READ_USER
)
290 .put(&API_METHOD_UPDATE_USER
)
291 .delete(&API_METHOD_DELETE_USER
);
293 pub const ROUTER
: Router
= Router
::new()
294 .get(&API_METHOD_LIST_USERS
)
295 .post(&API_METHOD_CREATE_USER
)
296 .match_all("userid", &ITEM_ROUTER
);