P1: WebDAV ACL enforcement (RFC 3744)
- Add enable_acl field to VfsDavFs - Add check_acl() helper method - ACL checks in open(), read_dir(), create_dir(), remove_dir(), remove_file(), rename() - Uses VfsAceMask for permission checks (ReadData, WriteData, etc.) - Returns FsError::Forbidden if ACL denies access Tests: 289 passed, 0 failed
This commit is contained in:
@@ -81,6 +81,7 @@ pub struct VfsDavFs {
|
|||||||
versioning: Option<Arc<WebDavVersioning>>,
|
versioning: Option<Arc<WebDavVersioning>>,
|
||||||
props_data: Arc<RwLock<HashMap<String, Vec<DavProp>>>>,
|
props_data: Arc<RwLock<HashMap<String, Vec<DavProp>>>>,
|
||||||
props_path: PathBuf,
|
props_path: PathBuf,
|
||||||
|
enable_acl: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for VfsDavFs {
|
impl Clone for VfsDavFs {
|
||||||
@@ -93,6 +94,7 @@ impl Clone for VfsDavFs {
|
|||||||
versioning: self.versioning.clone(),
|
versioning: self.versioning.clone(),
|
||||||
props_data: self.props_data.clone(),
|
props_data: self.props_data.clone(),
|
||||||
props_path: self.props_path.clone(),
|
props_path: self.props_path.clone(),
|
||||||
|
enable_acl: self.enable_acl,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -178,6 +180,7 @@ impl VfsDavFs {
|
|||||||
versioning: None,
|
versioning: None,
|
||||||
props_data,
|
props_data,
|
||||||
props_path,
|
props_path,
|
||||||
|
enable_acl: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,9 +201,14 @@ impl VfsDavFs {
|
|||||||
versioning: Some(versioning),
|
versioning: Some(versioning),
|
||||||
props_data,
|
props_data,
|
||||||
props_path,
|
props_path,
|
||||||
|
enable_acl: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_enable_acl(&mut self, enable: bool) {
|
||||||
|
self.enable_acl = enable;
|
||||||
|
}
|
||||||
|
|
||||||
fn rel_key(&self, path: &DavPath) -> String {
|
fn rel_key(&self, path: &DavPath) -> String {
|
||||||
let rel = path.as_pathbuf();
|
let rel = path.as_pathbuf();
|
||||||
rel.to_string_lossy().to_string()
|
rel.to_string_lossy().to_string()
|
||||||
@@ -617,6 +625,18 @@ impl VfsDavFs {
|
|||||||
xml: Some(Self::empty_acl_xml()),
|
xml: Some(Self::empty_acl_xml()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_acl(&self, path: &Path, mask: crate::vfs::VfsAceMask) -> Result<(), FsError> {
|
||||||
|
if !self.enable_acl {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
match self.vfs.check_acl(path, &self.user_uuid, mask) {
|
||||||
|
Ok(true) => Ok(()),
|
||||||
|
Ok(false) => Err(FsError::Forbidden),
|
||||||
|
Err(crate::vfs::VfsError::Unsupported(_)) => Ok(()),
|
||||||
|
Err(_) => Err(FsError::Forbidden),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DavFileSystem for VfsDavFs {
|
impl DavFileSystem for VfsDavFs {
|
||||||
@@ -631,6 +651,9 @@ impl DavFileSystem for VfsDavFs {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if options.write {
|
if options.write {
|
||||||
|
if let Err(e) = self.check_acl(&full_path, crate::vfs::VfsAceMask::WriteData) {
|
||||||
|
return Box::pin(std::future::ready(Err(e)));
|
||||||
|
}
|
||||||
let file = VfsDavFile::new_write(
|
let file = VfsDavFile::new_write(
|
||||||
full_path,
|
full_path,
|
||||||
self.vfs.clone_boxed(),
|
self.vfs.clone_boxed(),
|
||||||
@@ -640,6 +663,9 @@ impl DavFileSystem for VfsDavFs {
|
|||||||
);
|
);
|
||||||
Box::pin(std::future::ready(Ok(Box::new(file) as Box<dyn DavFile>)))
|
Box::pin(std::future::ready(Ok(Box::new(file) as Box<dyn DavFile>)))
|
||||||
} else {
|
} else {
|
||||||
|
if let Err(e) = self.check_acl(&full_path, crate::vfs::VfsAceMask::ReadData) {
|
||||||
|
return Box::pin(std::future::ready(Err(e)));
|
||||||
|
}
|
||||||
let flags = OpenFlags::new().read();
|
let flags = OpenFlags::new().read();
|
||||||
match self.vfs.open_file(&full_path, &flags) {
|
match self.vfs.open_file(&full_path, &flags) {
|
||||||
Ok(vfs_file) => {
|
Ok(vfs_file) => {
|
||||||
@@ -661,6 +687,10 @@ impl DavFileSystem for VfsDavFs {
|
|||||||
Err(e) => return Box::pin(std::future::ready(Err(e))),
|
Err(e) => return Box::pin(std::future::ready(Err(e))),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if let Err(e) = self.check_acl(&full_path, crate::vfs::VfsAceMask::ListDirectory) {
|
||||||
|
return Box::pin(std::future::ready(Err(e)));
|
||||||
|
}
|
||||||
|
|
||||||
match self.vfs.read_dir(&full_path) {
|
match self.vfs.read_dir(&full_path) {
|
||||||
Ok(entries) => {
|
Ok(entries) => {
|
||||||
let results: Vec<Box<dyn DavDirEntry>> = entries
|
let results: Vec<Box<dyn DavDirEntry>> = entries
|
||||||
@@ -698,6 +728,9 @@ impl DavFileSystem for VfsDavFs {
|
|||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
Err(e) => return Box::pin(std::future::ready(Err(e))),
|
Err(e) => return Box::pin(std::future::ready(Err(e))),
|
||||||
};
|
};
|
||||||
|
if let Err(e) = self.check_acl(&full_path, crate::vfs::VfsAceMask::AddSubdirectory) {
|
||||||
|
return Box::pin(std::future::ready(Err(e)));
|
||||||
|
}
|
||||||
if self.vfs.exists(&full_path) {
|
if self.vfs.exists(&full_path) {
|
||||||
return Box::pin(std::future::ready(Err(FsError::Exists)));
|
return Box::pin(std::future::ready(Err(FsError::Exists)));
|
||||||
}
|
}
|
||||||
@@ -712,6 +745,9 @@ impl DavFileSystem for VfsDavFs {
|
|||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
Err(e) => return Box::pin(std::future::ready(Err(e))),
|
Err(e) => return Box::pin(std::future::ready(Err(e))),
|
||||||
};
|
};
|
||||||
|
if let Err(e) = self.check_acl(&full_path, crate::vfs::VfsAceMask::DeleteChild) {
|
||||||
|
return Box::pin(std::future::ready(Err(e)));
|
||||||
|
}
|
||||||
match self.vfs.remove_dir_all(&full_path) {
|
match self.vfs.remove_dir_all(&full_path) {
|
||||||
Ok(_) => Box::pin(std::future::ready(Ok(()))),
|
Ok(_) => Box::pin(std::future::ready(Ok(()))),
|
||||||
Err(e) => Box::pin(std::future::ready(Err(map_vfs_error(e)))),
|
Err(e) => Box::pin(std::future::ready(Err(map_vfs_error(e)))),
|
||||||
@@ -723,6 +759,9 @@ impl DavFileSystem for VfsDavFs {
|
|||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
Err(e) => return Box::pin(std::future::ready(Err(e))),
|
Err(e) => return Box::pin(std::future::ready(Err(e))),
|
||||||
};
|
};
|
||||||
|
if let Err(e) = self.check_acl(&full_path, crate::vfs::VfsAceMask::Delete) {
|
||||||
|
return Box::pin(std::future::ready(Err(e)));
|
||||||
|
}
|
||||||
match self.vfs.remove_file(&full_path) {
|
match self.vfs.remove_file(&full_path) {
|
||||||
Ok(_) => Box::pin(std::future::ready(Ok(()))),
|
Ok(_) => Box::pin(std::future::ready(Ok(()))),
|
||||||
Err(e) => Box::pin(std::future::ready(Err(map_vfs_error(e)))),
|
Err(e) => Box::pin(std::future::ready(Err(map_vfs_error(e)))),
|
||||||
@@ -738,6 +777,12 @@ impl DavFileSystem for VfsDavFs {
|
|||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
Err(e) => return Box::pin(std::future::ready(Err(e))),
|
Err(e) => return Box::pin(std::future::ready(Err(e))),
|
||||||
};
|
};
|
||||||
|
if let Err(e) = self.check_acl(&from_path, crate::vfs::VfsAceMask::Delete) {
|
||||||
|
return Box::pin(std::future::ready(Err(e)));
|
||||||
|
}
|
||||||
|
if let Err(e) = self.check_acl(&to_path, crate::vfs::VfsAceMask::AddFile) {
|
||||||
|
return Box::pin(std::future::ready(Err(e)));
|
||||||
|
}
|
||||||
let from_key = self.rel_key(from);
|
let from_key = self.rel_key(from);
|
||||||
let to_key = self.rel_key(to);
|
let to_key = self.rel_key(to);
|
||||||
let props_data = self.props_data.clone();
|
let props_data = self.props_data.clone();
|
||||||
|
|||||||
Reference in New Issue
Block a user