]> git.proxmox.com Git - proxmox-backup.git/blobdiff - src/api2/reader.rs
src/config/acl.rs: introduce more/better datastore privileges
[proxmox-backup.git] / src / api2 / reader.rs
index e146f2c6e6c76f71bc996ff63cdc26bb5611826c..88206bd9199a402935a65711311eaba45d0da970 100644 (file)
@@ -1,5 +1,5 @@
 //use chrono::{Local, TimeZone};
-use failure::*;
+use anyhow::{bail, format_err, Error};
 use futures::*;
 use hyper::header::{self, HeaderValue, UPGRADE};
 use hyper::http::request::Parts;
@@ -7,14 +7,16 @@ use hyper::{Body, Response, StatusCode};
 use serde_json::Value;
 
 use proxmox::{sortable, identity};
-use proxmox::api::http_err;
-use proxmox::api::{ApiFuture, ApiHandler, ApiMethod, Router, RpcEnvironment};
+use proxmox::api::{ApiResponseFuture, ApiHandler, ApiMethod, Router, RpcEnvironment, Permission};
 use proxmox::api::schema::*;
+use proxmox::http_err;
 
 use crate::api2::types::*;
 use crate::backup::*;
 use crate::server::{WorkerTask, H2Service};
 use crate::tools;
+use crate::config::acl::PRIV_DATASTORE_READ;
+use crate::config::cached_user_info::CachedUserInfo;
 
 mod environment;
 use environment::*;
@@ -28,7 +30,7 @@ pub const API_METHOD_UPGRADE_BACKUP: ApiMethod = ApiMethod::new(
     &ObjectSchema::new(
         concat!("Upgraded to backup protocol ('", PROXMOX_BACKUP_READER_PROTOCOL_ID_V1!(), "')."),
         &sorted!([
-            ("store", false, &StringSchema::new("Datastore name.").schema()),
+            ("store", false, &DATASTORE_SCHEMA),
             ("backup-type", false, &StringSchema::new("Backup type.")
              .format(&ApiStringFormat::Enum(&["vm", "ct", "host"]))
              .schema()
@@ -41,6 +43,10 @@ pub const API_METHOD_UPGRADE_BACKUP: ApiMethod = ApiMethod::new(
             ("debug", true, &BooleanSchema::new("Enable verbose debug logging.").schema()),
         ]),
     )
+).access(
+    // Note: parameter 'store' is no uri parameter, so we need to test inside function body
+    Some("The user needs Datastore.Read privilege on /datastore/{store}."),
+    &Permission::Anybody
 );
 
 fn upgrade_to_backup_reader_protocol(
@@ -49,12 +55,17 @@ fn upgrade_to_backup_reader_protocol(
     param: Value,
     _info: &ApiMethod,
     rpcenv: Box<dyn RpcEnvironment>,
-) -> ApiFuture {
+) -> ApiResponseFuture {
 
     async move {
         let debug = param["debug"].as_bool().unwrap_or(false);
 
+        let username = rpcenv.get_user().unwrap();
         let store = tools::required_string_param(&param, "store")?.to_owned();
+
+        let user_info = CachedUserInfo::new()?;
+        user_info.check_privs(&username, &["datastore", &store], PRIV_DATASTORE_READ, false)?;
+
         let datastore = DataStore::lookup_datastore(&store)?;
 
         let backup_type = tools::required_string_param(&param, "backup-type")?;
@@ -75,7 +86,6 @@ fn upgrade_to_backup_reader_protocol(
             bail!("unexpected http version '{:?}' (expected version < 2)", parts.version);
         }
 
-        let username = rpcenv.get_user().unwrap();
         let env_type = rpcenv.env_type();
 
         let backup_dir = BackupDir::new(backup_type, backup_id, backup_time);
@@ -172,7 +182,7 @@ fn download_file(
     param: Value,
     _info: &ApiMethod,
     rpcenv: Box<dyn RpcEnvironment>,
-) -> ApiFuture {
+) -> ApiResponseFuture {
 
     async move {
         let env: &ReaderEnvironment = rpcenv.as_ref();
@@ -192,8 +202,8 @@ fn download_file(
 
         env.log(format!("download {:?}", path3));
 
-        let payload = tokio::codec::FramedRead::new(file, tokio::codec::BytesCodec::new())
-            .map_ok(|bytes| hyper::Chunk::from(bytes.freeze()));
+        let payload = tokio_util::codec::FramedRead::new(file, tokio_util::codec::BytesCodec::new())
+            .map_ok(|bytes| hyper::body::Bytes::from(bytes.freeze()));
 
         let body = Body::wrap_stream(payload);
 
@@ -223,7 +233,7 @@ fn download_chunk(
     param: Value,
     _info: &ApiMethod,
     rpcenv: Box<dyn RpcEnvironment>,
-) -> ApiFuture {
+) -> ApiResponseFuture {
 
     async move {
         let env: &ReaderEnvironment = rpcenv.as_ref();
@@ -258,7 +268,7 @@ fn download_chunk_old(
     param: Value,
     _info: &ApiMethod,
     rpcenv: Box<dyn RpcEnvironment>,
-) -> Result<ApiFuture, Error> {
+) -> Result<ApiResponseFuture, Error> {
 
     let env: &ReaderEnvironment = rpcenv.as_ref();
     let env2 = env.clone();
@@ -275,8 +285,8 @@ fn download_chunk_old(
         .map_err(move |err| http_err!(BAD_REQUEST, format!("open file {:?} failed: {}", path2, err)))
         .and_then(move |file| {
             env2.debug(format!("download chunk {:?}", path3));
-            let payload = tokio::codec::FramedRead::new(file, tokio::codec::BytesCodec::new())
-                .map_ok(|bytes| hyper::Chunk::from(bytes.freeze()));
+            let payload = tokio_util::codec::FramedRead::new(file, tokio_util::codec::BytesCodec::new())
+                .map_ok(|bytes| hyper::body::Bytes::from(bytes.freeze()));
 
             let body = Body::wrap_stream(payload);
 
@@ -303,7 +313,7 @@ fn speedtest(
     _param: Value,
     _info: &ApiMethod,
     _rpcenv: Box<dyn RpcEnvironment>,
-) -> ApiFuture {
+) -> ApiResponseFuture {
 
     let buffer = vec![65u8; 1024*1024]; // nonsense [A,A,A...]