Added create_folder method to MailStore trait; Add code to set

restrictive permissions on mail account folders;
This commit is contained in:
Nathan Fisher 2023-06-23 00:13:56 -04:00
parent dcb182e4d0
commit 3a25914ec5
3 changed files with 56 additions and 1 deletions

View file

@ -5,6 +5,7 @@ edition = "2021"
[dependencies] [dependencies]
digest = "0.10" digest = "0.10"
libc = "0.2.146"
rustls-pemfile = "1.0" rustls-pemfile = "1.0"
sha2 = "0.10" sha2 = "0.10"
time = "0.3" time = "0.3"
@ -12,6 +13,11 @@ x509-parser = "0.15"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies.pw]
git = "https://codeberg.org/jeang3nie/pw_rs.git"
default-features = false
features = [ "libc" ]
[dependencies.rustls] [dependencies.rustls]
version = "0.21" version = "0.21"
features = [ "dangerous_configuration" ] features = [ "dangerous_configuration" ]

View file

@ -1,4 +1,8 @@
use std::io::BufReader; use std::{
ffi::CString,
io::BufReader,
os::{fd::AsRawFd, unix::prelude::OpenOptionsExt},
};
use crate::prelude::Certificate; use crate::prelude::Certificate;
@ -149,6 +153,21 @@ impl MailStore for Filesystem {
Some(folder) Some(folder)
} }
fn create_folder(&self, user: &str, folder: &str) -> Result<(), io::Error> {
if self.has_mailuser(user) {
let user: Mailbox = user.parse().map_err(|e: ParseMailboxError| {
io::Error::new(io::ErrorKind::Other, e.to_string())
})?;
let user: Mailuser = user.into();
let mut path = self.path.clone();
path.push(&user.host.to_string());
path.push(&user.username);
path.push(folder);
fs::create_dir_all(&path)?;
}
Ok(())
}
fn get_message(&self, user: &str, folder: &str, id: &str) -> Option<Message> { fn get_message(&self, user: &str, folder: &str, id: &str) -> Option<Message> {
self.get_folder(user, folder) self.get_folder(user, folder)
.and_then(|f| f.messages.get(id).cloned()) .and_then(|f| f.messages.get(id).cloned())
@ -230,7 +249,22 @@ impl MailStore for Filesystem {
.create(true) .create(true)
.write(true) .write(true)
.truncate(true) .truncate(true)
.mode(0o2770)
.open(path)?; .open(path)?;
if let Some(pw) = pw::Passwd::getpw()
.map_err(|e: pw::Error| io::Error::new(io::ErrorKind::Other, e.to_string()))?
{
let groups = pw
.groups()
.map_err(|e: pw::Error| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
if let Some(gr) = groups.iter().find(|g| g.name == mb.username) {
unsafe {
if libc::fchown(fd.as_raw_fd(), pw.uid, gr.gid) != 0 {
return Err(io::Error::last_os_error());
}
}
}
}
let mut writer = BufWriter::new(fd); let mut writer = BufWriter::new(fd);
writer.write_all(blurb.as_bytes())?; writer.write_all(blurb.as_bytes())?;
} }

View file

@ -19,6 +19,8 @@ pub trait MailStore {
fn has_mailuser(&self, mailuser: &str) -> bool; fn has_mailuser(&self, mailuser: &str) -> bool;
/// Retreives all of the messages for this user /// Retreives all of the messages for this user
fn get_folder(&self, user: &str, folder: &str) -> Option<Folder>; fn get_folder(&self, user: &str, folder: &str) -> Option<Folder>;
/// Creates a folder for the specified user, if it doesn't already exist
fn create_folder(&self, user: &str, folder: &str) -> Result<(), Self::Error>;
/// Checks whether this server has a message with the given title for this user and if so /// Checks whether this server has a message with the given title for this user and if so
/// returns the message /// returns the message
fn get_message(&self, user: &str, folder: &str, id: &str) -> Option<Message>; fn get_message(&self, user: &str, folder: &str, id: &str) -> Option<Message>;
@ -97,6 +99,19 @@ impl MailStore for Domain {
.and_then(|u| u.folders.get(folder).cloned()) .and_then(|u| u.folders.get(folder).cloned())
} }
fn create_folder(&self, user: &str, folder: &str) -> Result<(), io::Error> {
self.users.get(user).cloned().and_then(|mut u| {
u.folders.insert(
folder.to_string(),
Folder {
name: folder.to_string(),
messages: HashMap::new(),
},
)
});
Ok(())
}
fn get_message(&self, user: &str, folder: &str, title: &str) -> Option<Message> { fn get_message(&self, user: &str, folder: &str, title: &str) -> Option<Message> {
self.users self.users
.get(user) .get(user)