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}
;
11 use crate::config
::cached_user_info
::CachedUserInfo
;
13 pub const PBS_PASSWORD_SCHEMA
: Schema
= StringSchema
::new("User Password.")
14 .format(&PASSWORD_FORMAT
)
24 description
: "List users (with config digest).",
26 items
: { type: user::User }
,
29 permission
: &Permission
::Anybody
,
30 description
: "Returns all or just the logged-in user, depending on privileges.",
37 mut rpcenv
: &mut dyn RpcEnvironment
,
38 ) -> Result
<Vec
<user
::User
>, Error
> {
40 let (config
, digest
) = user
::config()?
;
42 let userid
: Userid
= rpcenv
.get_user().unwrap().parse()?
;
43 let user_info
= CachedUserInfo
::new()?
;
45 let top_level_privs
= user_info
.lookup_privs(&userid
, &["access", "users"]);
46 let top_level_allowed
= (top_level_privs
& PRIV_SYS_AUDIT
) != 0;
48 let filter_by_privs
= |user
: &user
::User
| {
49 top_level_allowed
|| user
.userid
== userid
52 let list
:Vec
<user
::User
> = config
.convert_to_typed_array("user")?
;
54 rpcenv
["digest"] = proxmox
::tools
::digest_to_hex(&digest
).into();
56 Ok(list
.into_iter().filter(filter_by_privs
).collect())
67 schema
: SINGLE_LINE_COMMENT_SCHEMA
,
71 schema
: PBS_PASSWORD_SCHEMA
,
75 schema
: user
::ENABLE_USER_SCHEMA
,
79 schema
: user
::EXPIRE_USER_SCHEMA
,
83 schema
: user
::FIRST_NAME_SCHEMA
,
87 schema
: user
::LAST_NAME_SCHEMA
,
91 schema
: user
::EMAIL_SCHEMA
,
97 permission
: &Permission
::Privilege(&["access", "users"], PRIV_PERMISSIONS_MODIFY
, false),
101 pub fn create_user(password
: Option
<String
>, param
: Value
) -> Result
<(), Error
> {
103 let _lock
= open_file_locked(user
::USER_CFG_LOCKFILE
, std
::time
::Duration
::new(10, 0), true)?
;
105 let user
: user
::User
= serde_json
::from_value(param
)?
;
107 let (mut config
, _digest
) = user
::config()?
;
109 if let Some(_
) = config
.sections
.get(user
.userid
.as_str()) {
110 bail
!("user '{}' already exists.", user
.userid
);
113 let authenticator
= crate::auth
::lookup_authenticator(&user
.userid
.realm())?
;
115 config
.set_data(user
.userid
.as_str(), "user", &user
)?
;
117 user
::save_config(&config
)?
;
119 if let Some(password
) = password
{
120 authenticator
.store_password(user
.userid
.name(), &password
)?
;
135 description
: "The user configuration (with config digest).",
139 permission
: &Permission
::Or(&[
140 &Permission
::Privilege(&["access", "users"], PRIV_SYS_AUDIT
, false),
141 &Permission
::UserParam("userid"),
145 /// Read user configuration data.
146 pub fn read_user(userid
: Userid
, mut rpcenv
: &mut dyn RpcEnvironment
) -> Result
<user
::User
, Error
> {
147 let (config
, digest
) = user
::config()?
;
148 let user
= config
.lookup("user", userid
.as_str())?
;
149 rpcenv
["digest"] = proxmox
::tools
::digest_to_hex(&digest
).into();
162 schema
: SINGLE_LINE_COMMENT_SCHEMA
,
165 schema
: PBS_PASSWORD_SCHEMA
,
169 schema
: user
::ENABLE_USER_SCHEMA
,
173 schema
: user
::EXPIRE_USER_SCHEMA
,
177 schema
: user
::FIRST_NAME_SCHEMA
,
181 schema
: user
::LAST_NAME_SCHEMA
,
185 schema
: user
::EMAIL_SCHEMA
,
190 schema
: PROXMOX_CONFIG_DIGEST_SCHEMA
,
195 permission
: &Permission
::Or(&[
196 &Permission
::Privilege(&["access", "users"], PRIV_PERMISSIONS_MODIFY
, false),
197 &Permission
::UserParam("userid"),
201 /// Update user configuration.
204 comment
: Option
<String
>,
205 enable
: Option
<bool
>,
207 password
: Option
<String
>,
208 firstname
: Option
<String
>,
209 lastname
: Option
<String
>,
210 email
: Option
<String
>,
211 digest
: Option
<String
>,
212 ) -> Result
<(), Error
> {
214 let _lock
= open_file_locked(user
::USER_CFG_LOCKFILE
, std
::time
::Duration
::new(10, 0), true)?
;
216 let (mut config
, expected_digest
) = user
::config()?
;
218 if let Some(ref digest
) = digest
{
219 let digest
= proxmox
::tools
::hex_to_digest(digest
)?
;
220 crate::tools
::detect_modified_configuration_file(&digest
, &expected_digest
)?
;
223 let mut data
: user
::User
= config
.lookup("user", userid
.as_str())?
;
225 if let Some(comment
) = comment
{
226 let comment
= comment
.trim().to_string();
227 if comment
.is_empty() {
230 data
.comment
= Some(comment
);
234 if let Some(enable
) = enable
{
235 data
.enable
= if enable { None }
else { Some(false) }
;
238 if let Some(expire
) = expire
{
239 data
.expire
= if expire
> 0 { Some(expire) }
else { None }
;
242 if let Some(password
) = password
{
243 let authenticator
= crate::auth
::lookup_authenticator(userid
.realm())?
;
244 authenticator
.store_password(userid
.name(), &password
)?
;
247 if let Some(firstname
) = firstname
{
248 data
.firstname
= if firstname
.is_empty() { None }
else { Some(firstname) }
;
251 if let Some(lastname
) = lastname
{
252 data
.lastname
= if lastname
.is_empty() { None }
else { Some(lastname) }
;
254 if let Some(email
) = email
{
255 data
.email
= if email
.is_empty() { None }
else { Some(email) }
;
258 config
.set_data(userid
.as_str(), "user", &data
)?
;
260 user
::save_config(&config
)?
;
274 schema
: PROXMOX_CONFIG_DIGEST_SCHEMA
,
279 permission
: &Permission
::Or(&[
280 &Permission
::Privilege(&["access", "users"], PRIV_PERMISSIONS_MODIFY
, false),
281 &Permission
::UserParam("userid"),
285 /// Remove a user from the configuration file.
286 pub fn delete_user(userid
: Userid
, digest
: Option
<String
>) -> Result
<(), Error
> {
288 let _lock
= open_file_locked(user
::USER_CFG_LOCKFILE
, std
::time
::Duration
::new(10, 0), true)?
;
290 let (mut config
, expected_digest
) = user
::config()?
;
292 if let Some(ref digest
) = digest
{
293 let digest
= proxmox
::tools
::hex_to_digest(digest
)?
;
294 crate::tools
::detect_modified_configuration_file(&digest
, &expected_digest
)?
;
297 match config
.sections
.get(userid
.as_str()) {
298 Some(_
) => { config.sections.remove(userid.as_str()); }
,
299 None
=> bail
!("user '{}' does not exist.", userid
),
302 user
::save_config(&config
)?
;
307 const ITEM_ROUTER
: Router
= Router
::new()
308 .get(&API_METHOD_READ_USER
)
309 .put(&API_METHOD_UPDATE_USER
)
310 .delete(&API_METHOD_DELETE_USER
);
312 pub const ROUTER
: Router
= Router
::new()
313 .get(&API_METHOD_LIST_USERS
)
314 .post(&API_METHOD_CREATE_USER
)
315 .match_all("userid", &ITEM_ROUTER
);