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>>,
|
||||
props_data: Arc<RwLock<HashMap<String, Vec<DavProp>>>>,
|
||||
props_path: PathBuf,
|
||||
enable_acl: bool,
|
||||
}
|
||||
|
||||
impl Clone for VfsDavFs {
|
||||
@@ -93,6 +94,7 @@ impl Clone for VfsDavFs {
|
||||
versioning: self.versioning.clone(),
|
||||
props_data: self.props_data.clone(),
|
||||
props_path: self.props_path.clone(),
|
||||
enable_acl: self.enable_acl,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -178,6 +180,7 @@ impl VfsDavFs {
|
||||
versioning: None,
|
||||
props_data,
|
||||
props_path,
|
||||
enable_acl: true,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -198,9 +201,14 @@ impl VfsDavFs {
|
||||
versioning: Some(versioning),
|
||||
props_data,
|
||||
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 {
|
||||
let rel = path.as_pathbuf();
|
||||
rel.to_string_lossy().to_string()
|
||||
@@ -617,6 +625,18 @@ impl VfsDavFs {
|
||||
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 {
|
||||
@@ -631,6 +651,9 @@ impl DavFileSystem for VfsDavFs {
|
||||
};
|
||||
|
||||
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(
|
||||
full_path,
|
||||
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>)))
|
||||
} 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();
|
||||
match self.vfs.open_file(&full_path, &flags) {
|
||||
Ok(vfs_file) => {
|
||||
@@ -661,6 +687,10 @@ impl DavFileSystem for VfsDavFs {
|
||||
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) {
|
||||
Ok(entries) => {
|
||||
let results: Vec<Box<dyn DavDirEntry>> = entries
|
||||
@@ -698,6 +728,9 @@ impl DavFileSystem for VfsDavFs {
|
||||
Ok(p) => p,
|
||||
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) {
|
||||
return Box::pin(std::future::ready(Err(FsError::Exists)));
|
||||
}
|
||||
@@ -712,6 +745,9 @@ impl DavFileSystem for VfsDavFs {
|
||||
Ok(p) => p,
|
||||
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) {
|
||||
Ok(_) => Box::pin(std::future::ready(Ok(()))),
|
||||
Err(e) => Box::pin(std::future::ready(Err(map_vfs_error(e)))),
|
||||
@@ -723,6 +759,9 @@ impl DavFileSystem for VfsDavFs {
|
||||
Ok(p) => p,
|
||||
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) {
|
||||
Ok(_) => Box::pin(std::future::ready(Ok(()))),
|
||||
Err(e) => Box::pin(std::future::ready(Err(map_vfs_error(e)))),
|
||||
@@ -738,6 +777,12 @@ impl DavFileSystem for VfsDavFs {
|
||||
Ok(p) => p,
|
||||
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 to_key = self.rel_key(to);
|
||||
let props_data = self.props_data.clone();
|
||||
|
||||
Reference in New Issue
Block a user