]> git.proxmox.com Git - proxmox-backup.git/blame - src/api2/access/user.rs
remove timer and lock functions, fix building with proxmox 0.3.2
[proxmox-backup.git] / src / api2 / access / user.rs
CommitLineData
f7d4e4b5 1use anyhow::{bail, Error};
579728c6
DM
2use serde_json::Value;
3
d4f020f4 4use proxmox::api::{api, ApiMethod, Router, RpcEnvironment, Permission};
579728c6 5use proxmox::api::schema::{Schema, StringSchema};
98c259b4 6use proxmox::tools::fs::open_file_locked;
579728c6
DM
7
8use crate::api2::types::*;
9use crate::config::user;
4f66423f 10use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_PERMISSIONS_MODIFY};
579728c6
DM
11
12pub const PBS_PASSWORD_SCHEMA: Schema = StringSchema::new("User Password.")
13 .format(&PASSWORD_FORMAT)
14 .min_length(5)
15 .max_length(64)
16 .schema();
17
18#[api(
19 input: {
20 properties: {},
21 },
22 returns: {
23 description: "List users (with config digest).",
24 type: Array,
0fafac24 25 items: { type: user::User },
579728c6 26 },
d4f020f4 27 access: {
74c08a57 28 permission: &Permission::Privilege(&["access", "users"], PRIV_SYS_AUDIT, false),
d4f020f4 29 },
579728c6
DM
30)]
31/// List all users
32pub fn list_users(
33 _param: Value,
34 _info: &ApiMethod,
522c0da0
DC
35 mut rpcenv: &mut dyn RpcEnvironment,
36) -> Result<Vec<user::User>, Error> {
579728c6
DM
37
38 let (config, digest) = user::config()?;
39
522c0da0
DC
40 let list = config.convert_to_typed_array("user")?;
41
42 rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into();
579728c6 43
522c0da0 44 Ok(list)
579728c6
DM
45}
46
47#[api(
48 protected: true,
49 input: {
50 properties: {
51 userid: {
52 schema: PROXMOX_USER_ID_SCHEMA,
53 },
54 comment: {
55 schema: SINGLE_LINE_COMMENT_SCHEMA,
56 optional: true,
57 },
58 password: {
59 schema: PBS_PASSWORD_SCHEMA,
60 optional: true,
61 },
62 enable: {
63 schema: user::ENABLE_USER_SCHEMA,
64 optional: true,
65 },
66 expire: {
67 schema: user::EXPIRE_USER_SCHEMA,
68 optional: true,
69 },
70 firstname: {
71 schema: user::FIRST_NAME_SCHEMA,
72 optional: true,
73 },
74 lastname: {
75 schema: user::LAST_NAME_SCHEMA,
76 optional: true,
77 },
78 email: {
79 schema: user::EMAIL_SCHEMA,
80 optional: true,
81 },
82 },
83 },
d4f020f4 84 access: {
74c08a57 85 permission: &Permission::Privilege(&["access", "users"], PRIV_PERMISSIONS_MODIFY, false),
d4f020f4 86 },
579728c6
DM
87)]
88/// Create new user.
7d4e3629 89pub fn create_user(password: Option<String>, param: Value) -> Result<(), Error> {
579728c6 90
98c259b4 91 let _lock = open_file_locked(user::USER_CFG_LOCKFILE, std::time::Duration::new(10, 0))?;
579728c6 92
7d4e3629 93 let user: user::User = serde_json::from_value(param)?;
579728c6
DM
94
95 let (mut config, _digest) = user::config()?;
96
7d4e3629
DM
97 if let Some(_) = config.sections.get(&user.userid) {
98 bail!("user '{}' already exists.", user.userid);
579728c6
DM
99 }
100
7d4e3629 101 let (username, realm) = crate::auth::parse_userid(&user.userid)?;
7d817b03 102 let authenticator = crate::auth::lookup_authenticator(&realm)?;
579728c6 103
7d4e3629 104 config.set_data(&user.userid, "user", &user)?;
579728c6
DM
105
106 user::save_config(&config)?;
107
7d817b03
DM
108 if let Some(password) = password {
109 authenticator.store_password(&username, &password)?;
110 }
111
579728c6
DM
112 Ok(())
113}
114
115#[api(
116 input: {
117 properties: {
118 userid: {
119 schema: PROXMOX_USER_ID_SCHEMA,
120 },
685e1334 121 },
579728c6
DM
122 },
123 returns: {
124 description: "The user configuration (with config digest).",
125 type: user::User,
126 },
d4f020f4 127 access: {
74c08a57 128 permission: &Permission::Privilege(&["access", "users"], PRIV_SYS_AUDIT, false),
d4f020f4 129 },
579728c6
DM
130)]
131/// Read user configuration data.
522c0da0 132pub fn read_user(userid: String, mut rpcenv: &mut dyn RpcEnvironment) -> Result<user::User, Error> {
579728c6 133 let (config, digest) = user::config()?;
522c0da0
DC
134 let user = config.lookup("user", &userid)?;
135 rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into();
136 Ok(user)
579728c6
DM
137}
138
139#[api(
140 protected: true,
141 input: {
142 properties: {
143 userid: {
144 schema: PROXMOX_USER_ID_SCHEMA,
145 },
146 comment: {
147 optional: true,
148 schema: SINGLE_LINE_COMMENT_SCHEMA,
149 },
150 password: {
151 schema: PBS_PASSWORD_SCHEMA,
152 optional: true,
153 },
154 enable: {
155 schema: user::ENABLE_USER_SCHEMA,
156 optional: true,
157 },
158 expire: {
159 schema: user::EXPIRE_USER_SCHEMA,
160 optional: true,
161 },
162 firstname: {
163 schema: user::FIRST_NAME_SCHEMA,
164 optional: true,
165 },
166 lastname: {
167 schema: user::LAST_NAME_SCHEMA,
168 optional: true,
169 },
170 email: {
171 schema: user::EMAIL_SCHEMA,
172 optional: true,
173 },
174 digest: {
175 optional: true,
176 schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
177 },
178 },
179 },
d4f020f4 180 access: {
74c08a57 181 permission: &Permission::Privilege(&["access", "users"], PRIV_PERMISSIONS_MODIFY, false),
d4f020f4 182 },
579728c6
DM
183)]
184/// Update user configuration.
185pub fn update_user(
186 userid: String,
187 comment: Option<String>,
188 enable: Option<bool>,
189 expire: Option<i64>,
190 password: Option<String>,
191 firstname: Option<String>,
192 lastname: Option<String>,
193 email: Option<String>,
194 digest: Option<String>,
195) -> Result<(), Error> {
196
98c259b4 197 let _lock = open_file_locked(user::USER_CFG_LOCKFILE, std::time::Duration::new(10, 0))?;
579728c6
DM
198
199 let (mut config, expected_digest) = user::config()?;
200
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)?;
204 }
205
206 let mut data: user::User = config.lookup("user", &userid)?;
207
208 if let Some(comment) = comment {
209 let comment = comment.trim().to_string();
210 if comment.is_empty() {
211 data.comment = None;
212 } else {
213 data.comment = Some(comment);
214 }
215 }
216
217 if let Some(enable) = enable {
218 data.enable = if enable { None } else { Some(false) };
219 }
220
221 if let Some(expire) = expire {
222 data.expire = if expire > 0 { Some(expire) } else { None };
223 }
224
225 if let Some(password) = password {
7d817b03
DM
226 let (username, realm) = crate::auth::parse_userid(&userid)?;
227 let authenticator = crate::auth::lookup_authenticator(&realm)?;
228 authenticator.store_password(&username, &password)?;
579728c6
DM
229 }
230
231 if let Some(firstname) = firstname {
232 data.firstname = if firstname.is_empty() { None } else { Some(firstname) };
233 }
234
235 if let Some(lastname) = lastname {
236 data.lastname = if lastname.is_empty() { None } else { Some(lastname) };
237 }
238 if let Some(email) = email {
239 data.email = if email.is_empty() { None } else { Some(email) };
240 }
241
242 config.set_data(&userid, "user", &data)?;
243
244 user::save_config(&config)?;
245
246 Ok(())
247}
248
249#[api(
250 protected: true,
251 input: {
252 properties: {
253 userid: {
254 schema: PROXMOX_USER_ID_SCHEMA,
255 },
256 digest: {
257 optional: true,
258 schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
259 },
260 },
261 },
d4f020f4 262 access: {
74c08a57 263 permission: &Permission::Privilege(&["access", "users"], PRIV_PERMISSIONS_MODIFY, false),
d4f020f4 264 },
579728c6
DM
265)]
266/// Remove a user from the configuration file.
267pub fn delete_user(userid: String, digest: Option<String>) -> Result<(), Error> {
268
98c259b4 269 let _lock = open_file_locked(user::USER_CFG_LOCKFILE, std::time::Duration::new(10, 0))?;
579728c6
DM
270
271 let (mut config, expected_digest) = user::config()?;
272
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)?;
276 }
277
278 match config.sections.get(&userid) {
279 Some(_) => { config.sections.remove(&userid); },
280 None => bail!("user '{}' does not exist.", userid),
281 }
282
283 user::save_config(&config)?;
284
285 Ok(())
286}
287
288const ITEM_ROUTER: Router = Router::new()
289 .get(&API_METHOD_READ_USER)
290 .put(&API_METHOD_UPDATE_USER)
291 .delete(&API_METHOD_DELETE_USER);
292
293pub const ROUTER: Router = Router::new()
294 .get(&API_METHOD_LIST_USERS)
295 .post(&API_METHOD_CREATE_USER)
296 .match_all("userid", &ITEM_ROUTER);